二、节点的关系 1. 描述 DOM可以将任何HTML描绘成一个由多层节点构成的结构。每个节点都拥有各自的特点、数据和方法,也与其他节点存在某种关系。节点之间的关系构成了层次,而所有页面标记则表现为一个以特定节点为根节点的树形结构。本文将详细描述DOM间的节点关系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 firstChild lastChild +------------+ +----------+ -------------------------> | | Node | | | +----------> | | <----------------------+ | | | +----------+ parentNode | | | |parentNode ^ | | | | | | | | | | | | | | |parentNode | | | | | | v v +---+-+---+ nextSibling ++-------+ nextSibling ++--------+ | Node + -------------> | Node | ------------> | Node | | | <-------------+ | | <------------- | | +---------+ previousSibling +--------+ previousSibling +---------+
2. 属性 2.1 父级属性 2.1.1 parentNode parentNode是指定节点的父节点.一个元素节点的父节点可能是一个元素(Element )节点,也可能是一个文档(Document )节点,或者是个文档碎片(DocumentFragment)节点.
对于下面的节点类型 : Attr, Document, DocumentFragment, Entity, Notation,其parentNode属性返回null.
如果当前节点刚刚被建立,还没有被插入到DOM树中,则该节点的parentNode属性也返回null.
1 2 3 4 5 6 7 8 9 10 11 12 13 <div id ="myDiv" > </div > <script > console .log (myDiv.parentNode ); console .log (document .body .parentNode ); console .log (document .documentElement .parentNode ); console .log (document .parentNode ); var myDiv = document .getElementById ('myDiv' ); console .log (myDiv.parentNode ); var fragment = document .createDocumentFragment (); fragment.appendChild (myDiv); console .log (myDiv.parentNode ); </script >
Node.parentNode
2.1.2 parentElement 返回当前节点的父元素节点,如果该元素没有父节点,或者父节点不是一个元素节点.则 返回null.
1 2 3 4 5 6 7 <div id ="myDiv" > </div > <script > console .log (myDiv.parentElement ); console .log (document .body .parentElement ); console .log (document .documentElement .parentElement ); console .log (document .parentElement ); </script >
[注意]在IE浏览器中,只有Element元素节点才有该属性,其他浏览器则是所有类型的节点都有该属性
1 2 3 4 5 6 7 <div id ="test" > 123</div > <script > console .log (test.firstChild .parentElement ); console .log (test.parentElement ); </script >
2.2 子级属性 2.2.1 childNodes childNodes是一个只读的类数组对象NodeList对象 ,它保存着该节点的第一层子节点,该集合为即时更新的集合
1 2 3 4 5 6 <ul id ="myUl" > <li > <div > </div > </li > </ul > <script > var myUl = document .getElementById ('myUl' ); console .log (myUl.childNodes ); </script >
Node.childNodes MDN
2.2.2 children children是一个只读的类数组对象HTMLCollection对象 ,但它保存的是该节点的第一层元素子节点
1 2 3 4 5 6 7 8 <div id ="myDiv" > 123</div > <script > var myDiv = document .getElementById ('myDiv' ); console .log (myDiv.childNodes ); console .log (myDiv.children ); </script >
2.2.3 childElementCount:返回子元素节点的个数,相当于children.length 返回子元素节点的个数,相当于children.length
[注意]IE8-浏览器不支持
1 2 3 4 5 6 7 8 9 10 <ul id ="myUl" > <li > </li > <li > </li > </ul > <script > var myUl = document .getElementById ('myUl' );console .log (myUl.childNodes .length );console .log (myUl.children .length );console .log (myUl.childElementCount );</script >
2.2.4 firstChild:第一个子节点 2.2.5 lastChild:最后一个子节点 2.2.6 firstElementChild:第一个元素子节点 2.2.7 lastElementChild:最后一个元素子节点 上面四个属性,IE8-浏览器和标准浏览器的表现并不一致。IE8-浏览器不考虑空白文本节点,且不支持firstElementChild和lastElementChild
1 2 3 4 5 6 7 8 9 10 11 <ul id ="list" > <li > 1</li > <li > 2</li > <li > 3</li > </ul > <script > console .log (list.firstChild ); console .log (list.lastChild );console .log (list.firstElementChild );console .log (list.lastElementChild );</script >
2.3 同级属性 2.3.1 nextSibling:后一个节点 2.3.2 previousSibling:前一个节点 2.3.3 nextElementSibling:后一个元素节点 2.3.4 previousElementSibling:前一个元素节点 与子级属性类似,上面四个属性,IE8-浏览器和标准浏览器的表现并不一致。IE8-浏览器不考虑空白文本节点,且不支持nextElementSibling和previousElementSibling
1 2 3 4 5 6 7 8 9 10 11 12 <ul > <li > 1</li > <li id ="myLi" > 2</li > <li > 3</li > </ul > <script > var myLi = document .getElementById ('myLi' ); console .log (myLi.nextSibling ); console .log (myLi.nextElementSibling ); console .log (myLi.previousSibling ); console .log (myLi.previousElementSibling ); </script >
3. 方法 3.1 包含方法 3.1.1 hasChildNodes() hasChildNodes()方法在包含一个或多个子节点时返回true,比查询childNodes列表的length属性更简单
1 2 3 4 5 6 7 8 9 10 <div id ="one" > 123</div > <div id ="two" > </div > <script > var one = document .getElementById ('one' ); console .log (one.childNodes .length ); console .log (one.hasChildNodes ()); var two = document .getElementById ('two' ); console .log (two.childNodes .length ); console .log (two.hasChildNodes ()); </script >
3.1.2 contains() contains方法接受一个节点作为参数,返回一个布尔值,表示参数节点是否为当前节点的后代节点。参数为后代节点即可,不一定是第一层子节点
1 2 3 4 5 6 7 8 9 10 11 <div id ="myDiv" > <ul id ="myUl" > <li id ="myLi" > </li > <li > </li > </ul > </div > <script > console .log (myDiv.contains (myLi)); console .log (myDiv.contains (myUl)); console .log (myDiv.contains (myDiv)); </script >
[注意]IE和safari不支持document.contains()方法,只支持元素节点的contains()方法
1 2 console .log (document .contains (document .body ));
3.2 关系方法 3.2.1 compareDocumentPosition() compareDocumentPosition方法用于确定节点间的关系,返回一个表示该关系的位掩码
1 2 3 4 5 6 7 000000 0 两个节点相同 000001 1 两个节点不在同一个文档(即有一个节点不在当前文档) 000010 2 参数节点在当前节点的前面 000100 4 参数节点在当前节点的后面 001000 8 参数节点包含当前节点 010000 16 当前节点包含参数节点 100000 32 浏览器的私有用途
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <div id ="myDiv" > <ul id ="myUl" > <li id ="myLi1" > </li > <li id ="myLi2" > </li > </ul > </div > <script > console .log (myDiv.compareDocumentPosition (myUl)); console .log (myUl.compareDocumentPosition (myDiv)); console .log (myDiv.compareDocumentPosition (myDiv)); console .log (myLi1.compareDocumentPosition (myLi2)); console .log (myLi2.compareDocumentPosition (myLi1)); </script >
3.2.2 isSameNode()和isEqualNode() 这两个方法都接受一个节点参数,并在传入节点与引用节点相同或相等时返回true
所谓相同(same),指的是两个节点引用的是同一个对象
所谓相等(equal),指的是两个节点是相同的类型,具有相等的属性(nodeName、nodeValue等等),而且它们的attributes和childNodes属性也相等(相同位置包含相同的值)
[注意]firefox不支持isSameNode()方法,而IE8-浏览器两个方法都不支持
1 2 3 4 5 6 7 8 9 <script > var div1 = document .createElement ('div' ); div1.setAttribute ("title" ,"test" ); var div2 = document .createElement ('div' ); div2.setAttribute ("title" ,"test" ); console .log (div1.isSameNode (div1)); console .log (div1.isEqualNode (div2)); console .log (div1.isSameNode (div2)); </script >
4. 参考资料 深入理解DOM节点关系
深入理解DOM节点类型第五篇——元素节点Element
深入理解javascript中的动态集合——NodeList、HTMLCollection和NamedNodeMap