Author: valentinogagliardi
Translator: Front-end wisdom
Source: making
Everyone said there was no project on your resume, so I found one and gave it away【 Construction tutorial 】.
Document Object Model (DOM)
JS has a lot to tease us about, but it’s not that bad. As a scripting language that runs in a browser, it is very useful for processing Web pages. In this article, we’ll see what methods we have to interact with and modify HTML documents and their elements. But first let’s demystify the Document Object Model.
The document Object Model is a fundamental concept that underlies everything we do in browsers. But what exactly is that? When we visit a Web page, the browser tells us how to interpret each HTML element. This creates a virtual representation of the HTML document and stores it in memory. The HTML page is transformed into a tree structure, with each HTML element becoming a leaf connected to the parent branch. Consider this simple HTML page:
<! DOCTYPE html> <html lang="en"> <head> <title>A super simple title! </title> </head> <body> <h1>A super simple web page! </h1> </body> </htmlCopy the code
When the browser scans the HTML above, it creates a document object model, which is a mirror image of the HTML structure. At the top of this structure is a document, also known as the root element, that contains another element: HTML. The HTML element contains a head, which in turn has a title. Then the body with the h1. Each HTML element is represented by a specific type, also known as an interface, and may contain text or other nested elements
document (HTMLDocument)
|
| --> html (HTMLHtmlElement)
|
| --> head (HtmlHeadElement)
| |
| | --> title (HtmlTitleElement)
| | --> text: "A super simple title!"
|
| --> body (HtmlBodyElement)
| |
| | --> h1 (HTMLHeadingElement)
| | --> text: "A super simple web page!"
Copy the code
Every HTML Element is derived from Element, but a large number of them are further specialized. We can examine the prototype to find out what “category” the element belongs to. For example, the H1 element is HTMLHeadingElement
Document.quertselector ('h1').__proto__ // output: HTMLHeadingElementCopy the code
HTMLHeadingElement is the descendant of HTMLElement
document.querySelector('h1').__proto__.__proto__
// Output: HTMLElement
Copy the code
Element is a very versatile base class from which all objects under the Document object inherit. This interface describes methods and attributes that are common to all elements of the same kind. Interfaces that inherit from Element and add additional functionality describe specific behavior. For example, the HTMLElement interface is the base interface for all HTML elements, while the SVGElement interface is the base for all SVG elements. Most of the functionality is further defined in the hierarchy interface of the class.
At this point (especially for beginners), there can be some confusion between Document and Window. Window refers to the browser, and document refers to the current HTML page. The Window is a global object that can be accessed directly from any JS code running in the browser. It is not a “native” object of JS, but is exposed by the browser itself. Window has a number of properties and methods, as shown below:
window.alert('Hello world'); // Shows an alert
window.setTimeout(callback, 3000); // Delays execution
window.fetch(someUrl); // makes XHR requests
window.open(); // Opens a new tab
window.location; // Browser location
window.history; // Browser history
window.navigator; // The actual device
window.document; // The current page
Copy the code
Since these attributes are global, we can omit window as well:
alert('Hello world'); // Shows an alert
setTimeout(callback, 3000); // Delays execution
fetch(someUrl); // makes XHR requests
open(); // Opens a new tab
location; // Browser location
history; // Browser history
navigator; // The actual device
document; // The current page
Copy the code
You should already be familiar with some of these methods, such as setTimeout() or window.navigator, which retrieve the language used by the current browser:
if (window.navigator) {
var lang = window.navigator.language;
if (lang === "en-US") {
// show something
}
if (lang === "it-IT") {
// show something else
}
}
Copy the code
To learn more about methods on Windows, check out the MDN documentation. In the next section, let’s take a closer look at DOM.
Node, element, and DOM operations
The Document interface has a number of useful methods, such as querySelector(), which is used to select any HTML element within the current HTML page:
document.querySelector('h1');
Copy the code
Window represents the browser of the current window. The following instructions are the same as above:
window.document.querySelector('h1');
Copy the code
However, the following syntax is more common, and we’ll use it a lot in the next section:
document.methodName();
Copy the code
In addition to querySelector() for selecting HTML elements, there are many more useful methods
// Return a single element document.getElementById(' Testimonials '); / / return a HTMLCollection document. GetElementsByTagName (" p "); / / returns a nodelist document. QuerySelectorAll (" p ");Copy the code
Not only can we select HTML elements, but we can also interact with and modify their internal state. For example, if you want to read or change the internal contents of a given element:
// Read or write
document.querySelector('h1').innerHtml; // Read
document.querySelector('h1').innerHtml = ''; // Write! Ouch!
Copy the code
Each HTML element in the DOM is also a ** “node” **, and we can actually check the node type like this:
document.querySelector('h1').nodeType;
Copy the code
The above result returns 1, representing the identifier of the node that is of type Element. We can also check the node name:
document.querySelector('h1').nodeName;
"H1"
Copy the code
Here, the node name is returned in uppercase. Typically we deal with four types of nodes in the DOM
-
Document: Root node (nodeType 9)
-
Nodes of type Element: actual HTML tags (nodeType 1), such as
and
-
Nodes for type attributes: attributes for each HTML element (attributes)
-
Text node: the actual Text content of the element (nodeType 3)
Since elements are nodes, nodes can have properties (also called attributes) that we can examine and manipulate:
// Return true or false document.querySelector('a').hasattribute ('href'); // Return the text content of the attribute, or null document.querySelector('a').getAttribute('href'); // Set the given attribute document.querySelector('a').setattribute ('href', 'someLink');Copy the code
We said earlier that DOM is a tree-like structure. This feature is also reflected in HTML elements. Each element may have parent and child elements, which we can see by examining certain attributes of the element:
// Return an HTMLCollection document.children; // Return a list of nodes document.childNodes; // Returns a node document.querySelector('a').parentNode; // Return the HTML element document.querySelector('a').parentelement;Copy the code
You learned how to select and query HTML elements. What about creating elements? To create a new node of type Element, the native DOM API provides the createElement method:
var heading = document.createElement('h1');
Copy the code
Create a text node with createTextNode:
var text = document.createTextNode('Hello world');
Copy the code
You can combine the two nodes by attaching text to a new HTML element. Finally, you can also attach the heading element to the root document:
var heading = document.createElement('h1');
var text = document.createTextNode('Hello world');
heading.appendChild(text);
document.body.appendChild(heading);
Copy the code
You can also remove nodes from the DOM using the remove() method. Call a method on the element and the node will disappear from the page:
document.querySelector('h1').remove();
Copy the code
That’s all you need to know to start manipulating the DOM with JS in your browser. In the next section, we’ll use DOM flexibly, but first we need to take a detour, because we also need to talk about ** “DOM events” **.
DOM and events
DOM elements are smart. Not only can they contain text and other HTML elements, they can also “emit” and respond to “events.” Browse any web site and open the browser console. Select an element using the following command:
document.querySelector('p')
Copy the code
Look at this property
document.querySelector('p').onclick
Copy the code
What type is it:
typeof document.querySelector('p').onclick // "object"
Copy the code
“object”! Why is it called “onclick”? A little bit intuitively we can imagine that it’s some sort of magical property on the element that responds to clicks, right? Exactly.
If you’re interested, look at the prototype chain for any HTML element. You’ll see that each Element is also an Element, which in turn is a node, which in turn is an EventTarget. You can verify this using Instanceof.
document.querySelector('p') instanceof EventTarget // true
Copy the code
I’d love to call EventTarget the father of all HTML elements, but there’s no real inheritance in JS, it’s more like any HTML element can see the property of another connected object. Therefore, any HTML element has the same property as EventTarget: the ability to publish events.
But what exactly is the event? Take an HTML button. If you click on it, that’s an event. With this.onclick object, we can register events that will run whenever the element is clicked. The function passed to the event is called ** “event listener” or “event handle” **.
Events and Listening
There are three ways to register event listeners in the DOM. The first form is archaic and should be avoided because it couples logical operations with labels
<! <button onclick="console.log('clicked')"> </button>Copy the code
The second option depends on the object named after the event. For example, we can listen for the click event by registering a function on the object.onclick:
document.querySelector("button").onclick = handleClick; function handleClick() { console.log("Clicked!" ); }Copy the code
This syntax is more concise and is a good alternative to inline handlers. There is another modern form based on addEventListener:
document.querySelector("button").addEventListener("click", handleClick); function handleClick() { console.log("Clicked!" ); }Copy the code
Personally, I prefer this form, but if you want maximum browser compatibility, use the.on mode. Now that we have an HTML element and an event listener, let’s take a closer look at DOM events.
Event objects, event defaults, and event bubbling
Each function passed as an event handler receives an object named “event” by default
var button = document.querySelector("button");
button.addEventListener("click", handleClick);
function handleClick() {
console.log(event);
}
Copy the code
It can be used directly in the function body, but in my code I prefer to declare it explicitly as a parameter:
function handleClick(event) {
console.log(event);
}
Copy the code
Event objects are a “must have” because we can control the behavior of events by calling methods on them. Events actually have specific characteristics, notably “default” and “bubbling” **. Consider an HTML link. Create a new HTML file called click-event.html with the following tags:
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Click event</title> </head> <body> <div> <a href="/404.html">click me! </a> </div> </body> <script src="click-event.js"></script> </html>Copy the code
Run the file in your browser and try clicking the link. It will jump to a 404 screen. The default behavior of a click event on a link is to go to the actual page specified in the href attribute. But what if I told you there was a way to block the defaults? Type preventDefault(), which is available for the event object. Create a new file named click-event.js with the following code:
var button = document.querySelector("a");
button.addEventListener("click", handleClick);
function handleClick(event) {
event.preventDefault();
}
Copy the code
Refresh the page in your browser and try clicking the link now: it won’t jump. Because we prevent the browser’s “event default” link from being the only HTML element that isn’t the default action, the form has the same properties.
Another interesting feature occurs when AN HTML element is nested within another element. Consider the following HTML
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Nested events</title> </head> <body> <div id="outer"> I am the outer div <div id="inner"> I am the inner div </div> </div> </body> <script src="nested-events.js"></script> </html>Copy the code
And the following JS code:
// nested-events.js
var outer = document.getElementById('inner');
var inner = document.getElementById('outer');
function handleClick(event){
console.log(event);
}
inner.addEventListener('click', handleClick);
outer.addEventListener('click', handleClick);
Copy the code
There are two event listeners, one for the external div and one for the internal div. Click on the inner div exactly and you’ll see:
Two event objects are printed. This is the bubbling of events at work. It looks like a bug in the browser behavior and can be disabled using the stopPropagation() method, which is also called on the event object
// function handleClick(event) { event.stopPropagation(); console.log(event); } / / /Copy the code
Although the implementation looks poor, bubbling can be a surprise in cases where registering too many event listeners is really bad for performance. Consider the following example:
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Event bubbling</title> </head> <body> <ul> <li>one</li> <li>two</li> <li>three</li> <li>four</li> <li>five</li> </ul> </body> <script src="event-bubbling.js"></script> </html>Copy the code
How many event listeners do I need to register in the list if I want to listen to click events in the list concurrently? The answer is: one. All you need is a listener registered with ul to intercept all clicks on any LI:
// event-bubbling.js
var ul = document.getElementsByTagName("ul")[0];
function handleClick(event) {
console.log(event);
}
ul.addEventListener("click", handleClick);
Copy the code
As you can see, event bubbling is a practical way to improve performance. In practice, registering event listeners is an expensive operation for browsers, and can result in a performance penalty in the case of large element lists.
Generate tables with JS
Now let’s start coding. Given an array of objects, you want to dynamically generate an HTML table. HTML tables are represented by
elements. Each table can also have a header, represented by the element. The header can have one or more rows , each with a cell represented by aelement. As follows: |
---|
<table> <thead> <tr> <th>name</th> <th>height</th> <th>place</th> </tr> </thead> <! -- more stuff here! --> </table>Copy the code
More than that, in most cases, each table has a body, defined by , which in turn contains a set of rows . Each row can have cells containing actual data. Form cells are defined by < TD >. Complete as follows:
<table>
<thead>
<tr>
<th>name</th>
<th>height</th>
<th>place</th>
</tr>
</thead>
<tbody>
<tr>
<td>Monte Falco</td>
<td>1658</td>
<td>Parco Foreste Casentinesi</td>
</tr>
<tr>
<td>Monte Falterona</td>
<td>1654</td>
<td>Parco Foreste Casentinesi</td>
</tr>
</tbody>
</table>
Copy the code
The task now is to generate a table from an array of JS objects. First, create a new file called build-table.html with the following contents:
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Build a table</title> </head> <body> <table> <! -- here goes our data! --> </table> </body> <script src="build-table.js"></script> </html>Copy the code
Create another file called build-table.js in the same folder and start with the following array:
"use strict";
var mountains = [
{ name: "Monte Falco", height: 1658, place: "Parco Foreste Casentinesi" },
{ name: "Monte Falterona", height: 1654, place: "Parco Foreste Casentinesi" },
{ name: "Poggio Scali", height: 1520, place: "Parco Foreste Casentinesi" },
{ name: "Pratomagno", height: 1592, place: "Parco Foreste Casentinesi" },
{ name: "Monte Amiata", height: 1738, place: "Siena" }
];
Copy the code
Consider this table. First, we need a :
document.createElement('thead')
Copy the code
There’s nothing wrong with that, but a closer look at the MDN table documentation reveals an interesting detail.
is an HTMLTableElement that also contains interesting methods. . One of the most useful is HTMLTableElement createTHead (), it can help we need to create the < thead >.First, write a function generateTableHead that generates the thead tag
function generateTableHead(table) {
var thead = table.createTHead();
}
Copy the code
This function takes a selector and creates a on the given table:
function generateTableHead(table) {
var thead = table.createTHead();
}
var table = document.querySelector("table");
generateTableHead(table);
Copy the code
Open build-table. HTML in your browser: nothing. However, if you open the browser console, you can see a new attached to the table.
Next, populate the header content. Start by creating a row in it. There is another method can help: HTMLTableElement. The insertRow (). With this, we can extend the method:
function generateTableHead (table) {
var thead = table,createThead();
var row = thead.insertRow();
}
Copy the code
At this point, we can generate our row. By looking at the source array, we can see that any object in it has the information we need:
var mountains = [
{ name: "Monte Falco", height: 1658, place: "Parco Foreste Casentinesi" },
{ name: "Monte Falterona", height: 1654, place: "Parco Foreste Casentinesi" },
{ name: "Poggio Scali", height: 1520, place: "Parco Foreste Casentinesi" },
{ name: "Pratomagno", height: 1592, place: "Parco Foreste Casentinesi" },
{ name: "Monte Amiata", height: 1738, place: "Siena" }
];
Copy the code
This means we can pass another argument to our function: an array to iterate over to generate the header cells:
function generateTableHead(table, data) { var thead = table.createTHead(); var row = thead.insertRow(); for (var i = 0; i < data.length; i++) { var th = document.createElement("th"); var text = document.createTextNode(data[i]); th.appendChild(text); row.appendChild(th); }}Copy the code
Unfortunately, there is no native way to create cells, so resort to document.createElement(“th”). Also note that document.createTextNode(data[I]) is used to create text nodes and appendChild() is used to add new elements to each tag.
When elements are created and manipulated in this way, we call it “imperative” DOM manipulation. Modern front-end libraries solve this problem by supporting a “declarative” approach. Instead of ordering the browser step by step, we can declare which HTML elements we want, and the library takes care of the rest.
Going back to our code, we can use the first function as follows
var table = document.querySelector("table");
var data = Object.keys(mountains[0]);
generateTableHead(table, data);
Copy the code
Now we can go further and generate the data for the actual table. The next function will implement a similar logic to generateTableHead, but this time we need two nested for loops. In the innermost loop, another native method is used to create a series of TDS. Method is HTMLTableRowElement insertCell (). Add another function called generateTable to the file you created earlier
function generateTable(table, data) { for (var i = 0; i < data.length; i++) { var row = table.insertRow(); for (var key in data[i]) { var cell = row.insertCell(); var text = document.createTextNode(data[i][key]); cell.appendChild(text); }}}Copy the code
Call the above function, passing the HTML table and array of objects as arguments:
generateTable(table, mountains);
Copy the code
Let’s dig into the logic of generateTable. The data parameter is an array that corresponds to mountains. The outermost for loop iterates through the array and creates a row for each element:
function generateTable(table, data) {
for (var i = 0; i < data.length; i++) {
var row = table.insertRow();
// omitted for brevity
}
}
Copy the code
The innermost loop iterates through each key of any given object and creates a text node containing the key value for each object
function generateTable(table, data) { for (var i = 0; i < data.length; i++) { var row = table.insertRow(); for (var key in data[i]) { // inner loop var cell = row.insertCell(); var text = document.createTextNode(data[i][key]); cell.appendChild(text); }}}Copy the code
Final code:
var mountains = [ { name: "Monte Falco", height: 1658, place: "Parco Foreste Casentinesi" }, { name: "Monte Falterona", height: 1654, place: "Parco Foreste Casentinesi" }, { name: "Poggio Scali", height: 1520, place: "Parco Foreste Casentinesi" }, { name: "Pratomagno", height: 1592, place: "Parco Foreste Casentinesi" }, { name: "Monte Amiata", height: 1738, place: "Siena" } ]; function generateTableHead(table, data) { var thead = table.createTHead(); var row = thead.insertRow(); for (var i = 0; i < data.length; i++) { var th = document.createElement("th"); var text = document.createTextNode(data[i]); th.appendChild(text); row.appendChild(th); } } function generateTable(table, data) { for (var i = 0; i < data.length; i++) { var row = table.insertRow(); for (var key in data[i]) { var cell = row.insertCell(); var text = document.createTextNode(data[i][key]); cell.appendChild(text); }}}Copy the code
Where:
var table = document.querySelector("table");
var data = Object.keys(mountains[0]);
generateTable(table, mountains);
generateTableHead(table, data);
Copy the code
Execution Result:
Of course, our method can also be advanced, the next chapter will be introduced.
conclusion
The DOM is a virtual copy of a Web page that the Web browser keeps in memory. DOM manipulation refers to the creation, modification, and deletion of HTML elements from the DOM. In the past, we used to rely on jQuery for simpler tasks, but now the native API has matured enough to make jQuery obsolete. JQuery, on the other hand, isn’t going away anytime soon, but every JS developer must know how to manipulate the DOM using the native API.
There are a number of reasons for doing this, additional libraries increase load times and the size of JS applications. Not to mention DOM manipulation comes up a lot in interviews.
Each available HTML element in the DOM has an interface that exposes a number of attributes and methods. When in doubt about which method to use, refer to the MDN documentation. The most common ways to manipulate the DOM are document.createElement() for creating new HTML elements and document.createTextNode() for creating text nodes in the DOM. Last but not least is.appendChild (), which is used to attach a new HTML element or text node to an existing element.
HTML elements can also emit events, also known as DOM events. Notable events are “click,” “submit,” “Drag,” “drop,” and so on. DOM events have some special behaviors, such as “default” and bubbling.
JS developers can take advantage of these properties, especially for event bubbling, which are useful for speeding up event processing in the DOM. While a good understanding of native apis is a good thing, modern front-end libraries offer undeniable benefits. It is possible to build large JS applications with Angular, React, and Vue.
The bugs that may exist after code deployment cannot be known in real time. In order to solve these bugs, I spent a lot of time on log debugging. Incidentally, I recommend a good BUG monitoring tool for youFundebug.
**github.com/valentinoga…
communication
This article is updated every week, you can search wechat “big move the world” for the first time to read and urge more (one or two earlier than the blog hey), this article GitHub github.com/qq449245884… It has been included and sorted out a lot of my documents. Welcome Star and perfect. You can refer to the examination points for review in the interview.