Chapter 4 – Element Node Selecting
最后更新于:2022-04-01 04:39:15
## 4.1 Selecting a specific element node
The most common methods for getting a reference to a single element node are:
* *querySelector()*
* *getElementById()*
In the code below I leverage both of these methods to select an element node from the HTML document.
live code: [http://jsfiddle.net/domenlightenment/b4Rch](http://jsfiddle.net/domenlightenment/b4Rch)
~~~
<!DOCTYPE html>
<html lang="en">
<body>
<ul>
<li>Hello</li>
<li>big</li>
<li>bad</li>
<li id="last">world</li>
</ul>
<script>
console.log(document.querySelector('li').textContent); //logs Hello
console.log(document.getElementById('last').textContent); //logs world
</script>
</body>
</html>
~~~
The *getElementById()* method is pretty simple compared to the more robust *querySelector()* method. The*querySelector()* method permits a parameter in the form of a [CSS selector syntax](http://www.w3.org/TR/css3-selectors/#selectors). Basically you can pass this method a CSS 3 selector (e.g. *'#score>tbody>tr>td:nth-of-type(2)'*) which it will use to select a single element in the DOM.
### Notes
*querySelector()* will return the first node element found in the document based on the selector. For example, in the code example above we pass a selector that would select all the li's in CSS, but only the first one is returned.
*querySelector()* is also defined on element nodes. This allows for the method to limit (allows for context querying) its results to a specific vein of the DOM tree
## 4.2 Selecting/creating a list (aka *NodeList*) of element nodes
The most common methods for selecting/creating a list of nodes in an HTML document are:
* *querySelectorAll()*
* *getElementsByTagName()*
* *getElementsByClassName()*
Below we use all three of these methods to create a list of the *`<li>`* elements in the document.
live code: [http://jsfiddle.net/domenlightenment/nT7Lr](http://jsfiddle.net/domenlightenment/nT7Lr)
~~~
<!DOCTYPE html>
<html lang="en">
<body>
<ul>
<li class="liClass">Hello</li>
<li class="liClass">big</li>
<li class="liClass">bad</li>
<li class="liClass">world</li>
</ul>
<script>
//all of the methods below create/select the same list of <li> elements from the DOM
console.log(document.querySelectorAll('li'));
console.log(document.getElementsByTagName('li'));
console.log(document.getElementsByClassName('liClass'));
</script>
</body>
</html>
~~~
If its not clear the methods used in the code example above do not select a specific element, but instead creates a list (aka [*NodeLists*](https://developer.mozilla.org/En/DOM/NodeList)) of elements that you can select from.
### Notes
*NodeLists* created from *getElementsByTagName()* and *getElementsByClassName()* are considered live are will always reflect the state of the document even if the document is updated after the list is created/selected.
The *querySelectorAll()* method does not return a live list of elements. Meaning that the list created from*querySelectorAll()* is a snap shot of the document at the time it was created and is not reflective of the document as it changes. The list is static not live.
*querySelectorAll()*, *getElementsByTagName()*, and *getElementsByClassName* are also defined on element nodes. This allows for the method to limit its results to specific vein(s) of the DOM tree (e.g.*document.getElementById('header').getElementsByClassName('a')*).
I did not mention the *getElementsByName()* method as it not commonly leverage over other solutions but you should be aware of its existence for selecting form, img, frame, embed, and object elements from a document that all have the same name attribute value.
Passing either *querySelectorAll()* or *getElementsByTagName()* the string *'*'*, which generally means all, will return a list of all elements in the document.
Keep in mind that *childNodes* will also return a *NodeList* just like *querySelectorAll()*, *getElementsByTagName()*, and*getElementsByClassName*
The *NodeLists* are array like (but does not inherit array methods) lists/collections and have a read only *length* property
## 4.3 Selecting all immediate child element nodes
Using the *children* property from an element node we can get a list (aka [*HTMLCollection*](https://developer.mozilla.org/en/DOM/HTMLCollection)) of all the immediate children nodes that are element nodes. In the code below I use *children* to create a selection/list of all of the*`<li>`*'s contained wiithin the *`<ul>`*.
live code: [http://jsfiddle.net/domenlightenment/svfRC](http://jsfiddle.net/domenlightenment/svfRC)
~~~
<!DOCTYPE html>
<html lang="en">
<body>
<ul>
<li><strong>Hi</strong></li>
<li>there</li>
</ul>
<script>
var ulElement = document.querySelector('ul').children;
//logs a list/array of all immediate child element nodes
console.log(ulElement); //logs [<li>, <li>]
</script>
</body>
</html>
~~~
Notice that using *children* only gives us the immediate element nodes excluding any nodes (e.g. text nodes) that are not elements. If the element has no children then *children* will return an empty array-like-list.
### Notes
*HTMLCollection*'s contain elements in document order, that is they are placed in the array in the order the elements appear in the DOM
*HTMLCollection*'s are live, which means any change to the document will be reflected dynamically in the collection
## 4.4 Contextual element selecting
The methods *querySelector()*, *querySelectorAll()*, *getElementsByTagName()*, and*getElementsByClassName* typically accessed from the *document* object are also defined on element nodes. This allows for these methods to limit its results to specific vein(s) of the DOM tree. Or said another, you can select a specific context in which you would like the methods to search for element nodes by invoking these methods on element node objects.
live code: [http://jsfiddle.net/domenlightenment/fL6tV](http://jsfiddle.net/domenlightenment/fL6tV)
~~~
<!DOCTYPE html>
<html lang="en">
<body>
<div><ul><li class="liClass">Hello</li><li class="liClass">big</li><li class="liClass">bad</li><li class="liClass">world</li></ul></div>
<ul><li class="liClass">Hello</li></ul>
<script>
//select a div as the context to run the selecting methods only on the contents of the div
var div = document.querySelector('div');
console.log(div.querySelector('ul'));
console.log(div.querySelectorAll('li'));
console.log(div.getElementsByTagName('li'));
console.log(div.getElementsByClassName('liClass'));
</script>
</body>
</html>
~~~
These methods not only operate on the live dom but programatic DOM structures that are created in code as well.
live code: [http://jsfiddle.net/domenlightenment/CCnva](http://jsfiddle.net/domenlightenment/CCnva)
~~~
<!DOCTYPE html>
<html lang="en">
<body>
<script>
//create DOM structure
var divElm = document.createElement('div');
var ulElm = document.createElement('ul');
var liElm = document.createElement('li');
liElm.setAttribute('class','liClass');
ulElm.appendChild(liElm);
divElm.appendChild(ulElm);
//use selecting methods on DOM structure
console.log(divElm.querySelector('ul'));
console.log(divElm.querySelectorAll('li'));
console.log(divElm.getElementsByTagName('li'));
console.log(divElm.getElementsByClassName('liClass'));
</body>
</html>
~~~
## 4.5 Pre-configured selections/lists of element nodes
You should be aware that there are some legacy, pre-configured arrays-like-lists, containing element nodes from an HTML document. Below I list a couple of these (not the complete list) that might be handy to be aware of.
* document.all - all elements in HTML document
* document.forms - all `<form>` elements in HTML document
* document.images - all `<img>` elements in HTML document
* document.links - all `<a>` elements in HTML document
* document.scripts - all `<script>` elements in HTML document
* document.styleSheets - all `<link>` or `<style>` objects in HTML document
### Notes
These pre-configured arrays are constucted from the [HTMLCollection](https://developer.mozilla.org/en/DOM/HTMLCollection) interface/object, except *document.styleSheets* it uses*StyleSheetList*
*[HTMLCollection](https://developer.mozilla.org/en-US/docs/DOM/HTMLCollection)*'s are live just like *[NodeList](https://developer.mozilla.org/En/DOM/NodeList)*'s.
Oddly *document.all* is constucted from a* HTMLAllCollection* not an *HTMLCollection* and is not supported in Firefox
## 4.6 Verify an element will be selected using *matchesSelector()*
Using the *matchesSelector()* method we can determine if an element will match a selector string. For example say we want to determine if an `<li>` is the first child element of a *`<ul>`*. In the code example below I select the first*`<li>`* inside of the `<ul>`and then ask if that element matches the selector, *`li:first-child`*. Because it in fact does, the *matchesSelector()* method returns *true*.
live code: [http://jsfiddle.net/domenlightenment/9RayM](http://jsfiddle.net/domenlightenment/9RayM)
~~~
<!DOCTYPE html>
<html lang="en">
<body>
<ul>
<li>Hello</li>
<li>world</li>
</ul>
<script>
//fails in modern browser must use browser prefix moz, webkit, o, and ms
console.log(document.querySelector('li').matchesSelector('li:first-child')); //logs false
//prefix moz
//console.log(document.querySelector('li').mozMatchesSelector('li:first-child'));
//prefix webkit
//console.log(document.querySelector('li').webkitMatchesSelector('li:first-child'));
//prefix o
//console.log(document.querySelector('li').oMatchesSelector('li:first-child'));
//prefix ms
//console.log(document.querySelector('li').msMatchesSelector('li:first-child'));
</script>
</body>
</html>
~~~
### Notes
matchesSelector has not seen much love from the browsers as its usage is behind browser prefixes *mozMatchesSelector()*,*webkitMatchesSelector()*, *oMatchesSelector()*, *msMatchesSelector()*
In the future *matchesSelector()* will be renamed to *matches()*