jacascript DOM节点——节点关系与操作

Posted 学习的时候不说话

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jacascript DOM节点——节点关系与操作相关的知识,希望对你有一定的参考价值。

前言:这是笔者学习之后自己的理解与整理。如果有错误或者疑问的地方,请大家指正,我会持续更新!

节点关系

  DOM 可以将任何html描绘成一个由多层节点构成的结构。每个节点都拥有各自的特点、数据和方法,也与其他节点存在某种关系。节点之间的关系构成了层次,而所有页面标签则表现为一个以特定节点为根节点的树形结构,也就是 DOM 树。下图为各节点之间的关系:

  

父级属性

parentNode 和 parentElement

  每个节点都有一个 parentNode 属性,该属性指向文档树中的父节点。对于一个节点来说,它的父节点只可能是三种类型:document节点、element节点和documentfragment节点。如果不存在,则返回null;

  document 是一个文档对象,使用 document 对象可以对 HTML 文档进行检查、修改或添加内容,并处理该文档内部的事件。浏览器打开一个 HTML 文档时,该文档就成了一个 document 对象,Document 对象使我们可以对 HTML 页面中的所有元素进行访问。它是 window 对象的一部分,可用 window.document,往往省略 window。

  document 对象是文档的根节点,documentElement 属性是文档的根元素 html。

  document.childNodes 属性返回该对象的所有子节点;对 HTML 文档来说,document 对象一般有两个子节点;

  第一个子节点是 document.doctype,表示文档类型节点(DocumentType)。对 HTML5 文档来说,该对象就是 <!DOCTYPE html> ;

  第二个子节点是 document.documentElement,表示元素节点(Element)。也就是 <html>;

 

  与 parentNode 属性不同的是,parentElement 返回的是父元素节点;在IE浏览器中,只有 Element 元素节点才有该属性,其他浏览器则是所有类型的节点都有该属性;

  parentElement 匹配的是 parent 为 element 的情况,而 parentNode 匹配的则是 parent 为 node 的情况。element 是包含在 node 里的,它的 nodeType 是1。

  一般情况 parentNode 可以取代 parentElement 的所有功能

        <div id="parent">
            <div id="child"></div>
        </div>
        <script type="text/javascript">
            var oParent = document.getElementById(\'parent\');
            var oChild = document.getElementById(\'child\');
            
            console.log(oChild.parentElement); //<div id="parent">...</div>
            console.log(oChild.parentNode);//<div id="parent">...</div>
        </script>

 

子级属性

childNodes 和 children

  childNodes 是一个只读的类数组对象,它保存着该节点的第一层子节点(包括空文本节点)

  children 是一个只读的类数组对象,但它保存的是该节点的第一层元素子节点(不包含空白文本节点)

childElementCount 和 children.length

  childElementCount 是返回子元素节点的个数;

  children.length 是返回子节点的长度;

其次,还有 firstChild 和 firstElementChild 的不同,lastChild 和 lastElementChild 的不同;

        <div id="parent">
            <div id="child"></div>
        </div>
        <script type="text/javascript">
            var oParent = document.getElementById(\'parent\');
            var oChild = document.getElementById(\'child\');
            
            console.log(oChild.parentElement); //<div id="parent">...</div>
            console.log(oChild.parentNode);//<div id="parent">...</div>
            
            //childNodes 是一个只读的类数组对象,它保存着该节点的第一层子节点(包括空文本节点);
            console.log(oParent.childNodes);//[text, div#child, text]
            console.log(oParent.childNodes.length);//3
            console.log(oParent.childElementCount);//1
            
            //children 是一个只读的类数组对象,但它保存的是该节点的第一层元素子节点;
            console.log(oParent.children);//[div#child]
            console.log(oParent.children.length);//1
            
            console.log(oParent.firstChild);//#text
            console.log(oParent.firstElementChild);//<div id="child"></div>
            
            console.log(oParent.lastChild);//#text
            console.log(oParent.lastElementChild);//<div id="child"></div>
        </script>

 

同级属性

nextSibling 和 nextElementSibling

  nextSibling 是后一个节点(包括文本节点);

  nextElementSibling 是后一个元素节点

previousSibling previousElementSibling

  previousSibling 是前一个节点(包括文本节点);

  previousElementSibling 是前一个元素节点

        <div id="parent">
            <div id="child1"></div>
            <div id="child2"></div>
            <div id="child3"></div>
        </div>
        <script type="text/javascript">
            var oParent = document.getElementById(\'parent\');
            var oChild2 = document.getElementById(\'child2\');
            
            console.log(oChild2.nextSibling);//#text
            console.log(oChild2.nextElementSibling);//<div id="child3"></div>
            
            console.log(oChild2.previousSibling);//#text
            console.log(oChild2.previousElementSibling);//<div id="child1"></div>
        </script>

 

方法

hasChildNodes()

  obj.hasChildNodes() 方法在包含一个或多个子节点时返回 true,比查询 childNodes.length 是否 大于等于 1 (不等于0)更简单;

contains

  obj.contains(value) 方法接受一个节点作为参数,返回一个布尔值,表示参数节点是否为当前节点的后代节点(不一定是第一层子节点)

  IE 和 safari 不支持 document.contains() 方法,只支持元素节点的 contains() 方法

        <div id="parent">
            <div id="child1"></div>
            <div id="child2"></div>
            <div id="child3">123</div>
        </div>
        <script type="text/javascript">
            var oParent = document.getElementById(\'parent\');
            var oChild2 = document.getElementById(\'child2\');
            var oChild3 = document.getElementById(\'child3\');
            
            console.log(oParent.hasChildNodes());//true
            console.log(oChild2.hasChildNodes());//false
            console.log(oChild3.hasChildNodes());//true
            
            console.log(oParent.contains(oChild2));//true
        </script>

 

compareDocumentPosition()

  obj1.compareDocumentPosition(obj2); 方法用于确定节点 obj1 和节点 obj2 之间的关系,返回一个表示该关系的位掩码;

  •  0     两个节点相同
  •    1     两个节点不在同一个文档(即有一个节点不在当前文档)
  •    2     参数节点 obj2 在当前节点 obj1 的前面
  •    4     参数节点 obj2 在当前节点 obj1 的后面
  •    8     参数节点 obj2 包含 当前节点 obj1
  •    16    当前节点 obj1 包含 参数节点 obj2
  •    32    浏览器的私有用途

  因为返回值会相加,我们一般看返回值是否大于16,来判断当前节点 obj1 是否包含 参数节点 obj2

        <div id="parent">
            <div id="child1"></div>
            <div id="child2"></div>
            <div id="child3">123</div>
        </div>
        <script type="text/javascript">
            var oParent = document.getElementById(\'parent\');
            var oChild2 = document.getElementById(\'child2\');
            var oChild3 = document.getElementById(\'child3\');
            
            //两节点相同
            console.log(oParent.compareDocumentPosition(oParent));//0
            
            //参数节点在在当前节点前面
            console.log(oChild3.compareDocumentPosition(oChild2));//2
            
            //参数节点在当前节点后面
            console.log(oChild2.compareDocumentPosition(oChild3));//4
            
            // 20=16+4 
            // 当前节点包含参数节点,并且参数节点在当前节点后面
            console.log(oParent.compareDocumentPosition(oChild2));//20
            
            // 10=8+2
            // 参数节点包含当前节点,并且参数节点在当前节点前面
            console.log(oChild2.compareDocumentPosition(oParent));//10
        </script>

 

isSameNode() 和 isEqualNode()

  这两个方法都接受一个节点参数,并在 节点参数 与 引用节点 相同或相等时返回 true;

  所谓相同(same),指的是两个节点引用的是同一个对象;

  所谓相等(equal),指的是两个节点是相同的类型,具有相等的属性(nodeName、nodeValue等等),而且它们的 attributes 和 childNodes 属性也相等(相同位置包含相同的值);

  firefox 不支持 isSameNode() 方法,而 IE8 及以下两个方法都不支持;

        <div id="parent">
            <div id="child1"></div>
            <div id="child2"></div>
            <div id="child3"></div>
            
            <div class="child"></div>
            <div class="child"></div>
            <div class="child">1234</div>
        </div>
        <script type="text/javascript">
            var oParent = document.getElementById(\'parent\');
            var oChild2 = document.getElementById(\'child2\');
            var oChild3 = document.getElementById(\'child3\');
            
            var oChild = document.getElementsByClassName(\'child\');
            //isSameNode 指的是两个节点引用的是同一个对象;
            //isEqualNode 指的是两个节点是相同的类型,具有相等的属性(nodeName、nodeValue等等),并且
       //它们的 attributes 和 childNodes 属性也相等(相同位置包含相同的值);
console.log(oParent.isSameNode(oParent));//true console.log(oParent.isEqualNode(oParent));//true console.log(oChild2.isSameNode(oChild3));//false console.log(oChild2.isEqualNode(oChild3));//false console.log(oChild[0].isSameNode(oChild[1]));//false console.log(oChild[0].isEqualNode(oChild[1]));//true console.log(oChild[1].isEqualNode(oChild[2]));//false </script>

 

节点操作

  DOM 提供节点操作的方法是因为 DOM 节点关系指针都是只读的;

  DOM 节点操作方法包括创建节点、插入节点、删除节点、替换节点、查看节点和复制节点。查看节点指的是查看节点之间的关系,在上面已经做过详细介绍;

createElement() 创建节点

  document.createElement() 方法可以创建新元素节点。这个方法接受一个参数,即要创建元素的标签名,这个标签名在 HTML 文档中不区分大小写;

  在IE7及以下浏览器中,创建 input 中的 button、checkbox 和 radio 可能出现兼容性问题,要单独处理下;

        <div id="wrapper"></div>
        <script type="text/javascript">
            var oWrapper = document.getElementById(\'wrapper\');
            var test = document.createElement(\'span\');
            
            oWrapper.appendChild(test);
            console.log(oWrapper);//<div id="wrapper"><span></span></div>
        </script>

   

插入节点

appendChild()

  appendChild() 方法用于向 childNodes 列表的末尾添加一个节点,并返回新增节点。

  如果插入的节点已经是文档的一部分了,那结果就是将该节点从原来的位置转移到新位置

        <div id="wrapper">
            <div id="child"></div>
            <div id="test"></div>
        </div>
        <script type="text/javascript">
            var oWrapper = document.getElementById(\'wrapper\');
            var oChild = document.getElementById(\'child\');
            var oTest = document.getElementById(\'test\');
            
            var oSpan = document.createElement(\'span\');
            oChild.appendChild(oSpan);
            oChild.appendChild(oTest);
            console.log(oWrapper);
            //<div id="wrapper">
            //<div id="child">
            //<span></span>
            //<div id="test"></div>
            //</div>
            //</div>
        </script>

 

insertBefore()

  referenceNode.parentNode.insertBefore(newNode,referenceNode) 方法接收两个参数:要插入的节点和作为参照的节点。

  插入节点后,被插入的节点会变成参照节点的前一个兄弟节点(previousSibling),同时被方法返回。

  如果参照节点是 null,则 insertBefore() 与 appendChild() 方法执行相同的操作,在父元素结尾插入新节点

  同样地,如果插入的节点已经是文档的一部分了,那结果就是将该节点从原来的位置转移到新位置;

        <div id="wrapper">
            <div id="child1"></div>
            <div id="child2"></div>
            <div id="child3"></div>
        </div>
        <script type="text/javascript">
            var oWrapper = document.getElementById(\'wrapper\');
            var oChild1 = document.getElementById(\'child1\');
            var oChild2 = document.getElementById(\'child2\');
            var oChild3 = document.getElementById(\'child3\');
            
            var test = document.createElement(\'span\');
            oWrapper.insertBefore(test,null);
            oWrapper.insertBefore(oChild2,oChild1);
            console.log(oWrapper);
            //<div id="wrapper">
            //<div id="child2"></div>
            //<div id="child1"></div>
            //<div id="child3"></div>
            //<span></span>
            //</div>
        </script>

  由于不存在 insertAfter() 方法,如果要插在当前节点的某个子节点后面,可以用 insertBefore() 和 appendChild() 封装方法;