Let's talk about DOM and DOM.
Introduction
Let's start with a chestnut:
<script type="text/javascript">var img = document.getElementsByTagName('img')[0];console.log('src:', img.src);</script>
Output src: sub/123.jpg? No, the output is src: http: // 127.0.0.1: 8020/sub/123.jpg, but I only want a pathname. Although there are 10 thousand ways to retrieve the pathname from the complete address, I still want to get the src we wrote in the attribute at one time.
Of course, such interfaces must be:
console.log('src:', img.getAttribute('src'));// src: /sub/123.jpg
In the past, I always thought there were not many things in HTML, But now I find that I don't know much about it, or too naive! The DOM structure is so unfamiliar. After finding the problem, I went back and looked at elevation 3. I always felt that the classification by DOM123 was not logical. I 'd like to summarize it by function.
DOM Node
First, let's look at the DOM structure hierarchy. The last chestnut:
<!DOCTYPE html>
This common HTML text already contains a common Node type. DOM organizes HTML documents in the form of a Node tree. That is to say, Node corresponds to the HTML document. Even the beautiful line breaks in the Code are actually reflected on the Node tree.
Nodelist corresponding to the above HTML:
The entire document is a document node, which we use more. Several attributes in document are rarely used: URL, domain, and referrer. The domain can be set to solve cross-domain problems between some subdomains. Other special sets, such as forms, images, and links, can be used to simplify the model during crawling.
Document contains common nodes such as document type, element, comment, and text.
Note the differences between the Text node and the element node. We usually write characters in the element node, but it does not mean that the element contains characters, instead, a text node is embedded in the element node, and the content in the text node is the character we write. For example, the <p> papapa </p> structure should be:
> Line feed
In addition, the line feed is often ignored. To beautify the code, we usually wrap lines between each tag. When DOM parses HTML documents, it also parses the line breaks into Textnode nodes! That is, each line of HTML code is followed by a textnode node \ n!
> Node relationship
When it comes to relationships, there are two types of relationships: parent-child relationship and sibling relationship. To locate a node, we need several positioning interfaces provided by DOM: firstChild, lastChild, previousSibling, nextSibling, and parentNode and childNodes. The combination of these interfaces can be used to locate a specific node.
Another point is Nodelist itself. Nodelist is a dynamic array object of classes. It dynamically means that after DOM changes, changes will be updated to Nodelist in real time. From this perspective, nodelist should be a reference set or pointer set. The array of classes means that people are not really arrays, but look a little like. So when traversing, using for in will also traverse some method attributes such as the object itself, or the general for I to length will be better, you can also use forEach and for.
> Node attributes
Each node has the corresponding nodetype, nodeName, and nodeValue attributes, which represent the node type, name, and value. Here, the element node's nodeName is the tag name, The nodeValue is null, and the text and comment's nodeValue are the corresponding strings.
DOM operations
When it comes to operations, it is nothing more than adding, deleting, modifying, and querying. In DOM operations, the subject is an element node, so it is basically an operation on the element node.
There are two types of DOM queries: accurate query and traversal query.
1) An exact query is a condition given for search. There are two main types of interfaces: getElementBy *** and querySelector ***.
The difference between the two types of queries lies in the real-time and non-real-time performance. The getElement ** method returns Nodelist, so it is real-time. QuerySelector ** returns a snapshot. Changes in the DOM table cannot be reflected in the query results in real time. Let's take a look at this example:
<Div class = "wrp"> <p> papapa </p> </div> <script> var divs = document. getElementsByClassName ('wrp '), // copy 7 // var divs = document. querySelectorAll ('. wrp '), // Copy 1 I, div = null; for (I = 0; I <divs. length; I ++) {div = divs [0]. cloneNode (true); document. body. appendChild (div); if (I> 5) {break ;}</script>
Using the getElements *** method, divs changes dynamically, so seven papapa copies are generated. If querySelector *** is used, divs only saves the status at the time of the query, so only one papapa is copied. Therefore, if you use the getElement Method for query, you need to use a len variable to save the current state. Otherwise, an endless loop will occur. According to our ordinary cognitive thinking, divs should not change dynamically. After all, I have not continued to query it. How can you change it. Therefore, the querySelector method is more controllable and does not produce some inexplicable bugs. In addition, the jQuery style must be liked by everyone.
2) Traversal
DOM provides two traversal iterators: NodeIterator and TreeWalker. Of course, you can also perform traversal manually.
The usage of NodeIterator is as follows:
1 <div class="wrp"> 2 <p>papapa</p> 3 <div> 4 <span>yohohoho</span> 5 <input class='input1' type="text" name="" value="" /> 6 </div> 7 <input class="input2" type="text" name="" value="" /> 8 </div> 9 <script> 10 var div = document.querySelector('.wrp'); 11 var filter = function(node) { 12 return node.tagName.toLowerCase() === 'input' ? 13 NodeFilter.FILTER_ACCEPT : 14 NodeFilter.FILTER_SKIP; 15 } 16 var myIterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT, filter, false); 17 var n = myIterator.nextNode(); // move to root(div) 18 while(n !== null) { 19 console.log(n.className); 20 n = myIterator.nextNode(); 21 } 22 </script>
TreeWalker traversal:
1 var div = document.querySelector('.wrp'); 2 var filter = function(node) { 3 return node.tagName.toLowerCase() === 'input' ? 4 NodeFilter.FILTER_ACCEPT : 5 NodeFilter.FILTER_SKIP; 6 } 7 8 var walker = document.createTreeWalker(div, NodeFilter.SHOW_ELEMENT, filter, false); 9 var n = walker.firstChild(); 10 while(n !== null) { 11 console.log(n.className); 12 n = walker.nextNode(); 13 }
In the manual mode, let's talk about the train of thought: first, we need to consider the sub-level as well as the sub-level. Obviously, we need to do this in the form of recursion to determine whether the node has a sub-node but recursion. Then there are some details. For example, in order to eliminate the influence of line breaks and text nodes, children is used directly to obtain sublevel nodes. In addition, we also need to avoid dynamic changes such as Nodelist. Check the Code:
1 function mywalker(el, filter, cb) { 2 var children = el.children; 3 for(var i = 0, len = children.length; i < len; i++) { 4 var walker = children[i]; 5 if(walker.children.length !== 0) { 6 mywalker(walker, filter, cb); 7 } else if(filter(walker)) { 8 cb(walker); 9 } 10 } 11 } 12 13 var div = document.querySelector('.wrp'); 14 15 function filter(node) { 16 return node.tagName.toLowerCase() === 'input'; 17 } 18 19 function cb(node) { 20 console.log(node.className); 21 } 22 23 mywalker(div, filter, cb);
If you want to consider text nodes, you can use childNodes to traverse them. In this case, you must filter line breaks.
The addition interfaces of DOM nodes include appendChild () and insertBefore (). However, you need to use the document. creat *** method and document. cloneNode () method to create a node (). After creating a node, add the node to the document through the Add interface. In addition to creating common nodes, you can also create scripts and style sheets. This method can be used to load resources on demand, delayed loading, and other loading methods. Of course, to create a loader like requirejs, you need to add a lot of processing logic.
You can delete two interfaces: replaceChild and removeChild.
1) Content Changes: innerHTML, innerText, textContent, and so on. TextContent is generally not used. It is a string that concatenates all text nodes in the node, including line breaks. Therefore, further string processing is required.
2) attribute changes
At the beginning of this article, we have already mentioned the two most common methods to change attributes, namely, Element. props = value and Element. setAttribute () series. GetAttribute () is the value on the Attribute node, that is, the string in the angle brackets <> Of the HTML Tag. If this parameter is not defined, a null value is returned. If yes, a string is returned. Element. props is used to query HTML Tag instances, that is, to query an instantiated Node object. During initialization, this object will set the attributes not defined in the HTML tag to "" and parse and convert them. Therefore, you can query the same object without defining attributes. prop returns a null value and getAttribute returns null. It queries event attributes such as style and onload. The former returns an object, and the latter returns a string or null. It queries custom attributes, the former returns an undefined, while the latter returns a custom value.
The results of the two types of queries at the beginning of the article are different because of this.
>Attributes
The attributes attribute is used to manage all attributes in a node. It is a NamedNodeMap and stores all attributes defined by the object. This product is actually a class array. Here chrome is clearly printed and clear at a glance. Do not use for in traversal.
You can use attributes ['id'] to query the corresponding attributes. It also has some methods, but no one will use it, in addition, the attributes attribute is rarely used. One of the scenarios for using it (or the only one) is to manage attributes in a centralized manner, or traverse or initialize attributes in batches. Generally, we use the. prop format, which is intuitive and convenient.
> Custom Attributes
We can add any custom attribute to the tag. Although we are free, we still need to have the specification. In HTML5, custom attributes are defined in the form of data-prop. Attributes attached to data can be managed in a unified manner through dataset attributes. Generally, data can be placed on data, and then the dataset attributes are directly read for rendering during rendering, the same is true for databases such as knockout.
> Style
The most important thing in attributes is style, which involves inline style, embedded style, and external style control. As mentioned above, you can use the element.stylt.sample to directly change the sample type, or use element.style.css Text to read and write all inline styles at a time. However, the style is complicated because of the overlay effects of embedded and external styles. Therefore, querying style alone cannot obtain the final style of the element. In this case, you can use the getComputedStyle () method of document. defaultView to obtain the calculation style, just like the chrome developer tool.
However,CSS is a big project. It is unreliable to try to dynamically control the changes of all styles through js. A more common practice is to preset various states in CSS, while js is used as a control to control state conversion, that is, to control class transformation. In DOM programming, apart from pure className, the more powerful interface is classList, which is also a class array object. It provides several easy-to-use Class Management Methods: add, contains, remove, toggle, and jQuery. But jQuery is a folk girl after all. It is inevitable to fall out of favor after the Orthodox harem absorbs all her odd-and-square techniques.
Summary
I have been pondering for a long time, but it is still messy and the structure is not clear enough. The structure hierarchy of DOM is based on Nodelist, and nodes of different nodeType form a DOM table. There are various interfaces for DOM operations, which may be confusing. Maybe this is why various frameworks have been trying to weaken developers' DOM operations. But if you are familiar with DOM operations on ultra-small scale applications, it is more flexible than the framework.
The summary of DOM is here. After reading it, we will organize it as the main component, supplemented by endorsement, and we must map it.