dom总结:节点层次

作者: 我不是大熊 | 来源:发表于2018-02-03 14:04 被阅读0次

    HTML可以描绘成一个多层节点构成的结构,文档节点是每个文档的根节点,<html>元素被称之为文档元素,是文档的最外层元素。不同的标记用不同的节点来表示。

    1. Node类型

    Node接口在Javascript中是作为Node类型实现的,除了IE之外,在其他所有浏览器中都可以访问到这个类型。而Javascript的所有节点类型都继承自Node类型。

    • 1.1nodeType属性

    表明节点类型:1.Node.ELEMENT_NODE,2.Node.ATTRIBUTE_NODE,3.Node.TEXT_NODE,4.Node.CDATA_SECTION_NODE,5.Node.ENTITY_REFERENCE_NODE,6.Node.ENTITY_NODE,7.Node.PROCESSING_INSTRUCTION_NODE,8.Node.COMMENT_NODE,9.Node.DOCUMENT_NODE,10.Node.DOCUMENT_TYPE_NODE,11.Node.DOCUMENT_FRAGMENT_NODE,12.Node.NOTATION_NODE

        var btn1 = document.getElementsByClassName('btn1')[0];
        if(btn1.nodeType == 1){
            console.log('这是元素节点');
        }
    
    • 1.2nodeName 和 nodeValue 属性
        //对于元素节点,nodeName中保存的始终都是元素的标签名,而nodeValue的值则始终为null
        console.log(btn1.nodeName);//这里是一个按钮,所以打印BUTTON
        console.log(btn1.nodeValue);
    
    • 1.3节点关系
      • childNodes:NodeList 对象,NodeList 对象是类数组对象,用于保存一组有序的节点。
        html:
        <ul class="ul-list"><li>第一行</li><li>第二行</li><li>第三行</li></ul>
    
        js:
        var ulList = document.getElementsByClassName('ul-list')[0];
        console.log(ulList.childNodes);
        var first = ulList.childNodes[0];
        console.log(first);
        var last = ulList.childNodes[ulList.childNodes.length-1];
        console.log(last);
    
        //hasChildNodes()方法判断是否有子节点
        console.log(ulList.hasChildNodes());
        //ownerDocument返回所在的文档,而且每个节点只能在一个文档中
        console.log(ulList.ownerDocument);
    
    • parentNode:父节点
    //打印ulList
    console.log(last.parentNode);
    
    • previousSibling和nextSibling
        console.log(second.previousSibling);//打印第三行
        console.log(second.nextSibling);//打印第一行
        console.log(last.nextSibling);//打印null
    
    • firstChild和lastChild
      console.log(ulList.firstChild);//打印第一行
      console.log(ulList.lastChild);//打印第三行
    
    • 1.4操作节点
      • appendChild()
        html:
        <div class="div-con">
            <p>div中的第一行</p>
            <p class="second-p">div中的第二行</p>
            <p>div中的第三行</p>
        </div>
    
        js:
        var div1 = document.getElementsByClassName('div-con')[0];
        var p = document.createElement("p");
        p.innerText = '这是新创建的段落';
        //返回值是被添加的子节点
        var appendP = div1.appendChild(p);
        console.log(appendP == p);
        //如果传入到 appendChild()中的节点已经是文档的一部分,那么就是将该节点从原来的位置转移到新位置
        var secondP = document.getElementsByClassName('second-p')[0];
        div1.appendChild(secondP);
    
    • insertBefore()
        var div1 = document.getElementsByClassName('div-con')[0];
        var secondP = document.getElementsByClassName('second-p')[0];
        var p = document.createElement("p");
        p.innerText = '这是新创建的段落';
        //insertBefore:指定放到某个子节点之前,如果第二个参数传null,则新节点会被放在最后
        div1.insertBefore(p,secondP);
    
    • replaceChild()
        var div1 = document.getElementsByClassName('div-con')[0];
        var secondP = document.getElementsByClassName('second-p')[0];
        var p = document.createElement("p");
        p.innerText = '这是新创建的段落';
        //replaceChild:替换子节点
        div1.replaceChild(p,secondP);
    
    • removeChild()
        var div1 = document.getElementsByClassName('div-con')[0];
        var secondP = document.getElementsByClassName('second-p')[0];
        //removeChild:删除子节点
        div1.removeChild(secondP);
    
    • 1.5其他方法
      • cloneNode()
        var ulList = document.getElementsByClassName('ul-list')[0];
        var div1 = document.getElementsByClassName('div-con')[0];
        //cloneNode:传是否深复制的参数,true为深复制(把子节点也复制过来),false则否.
        //事件处理程序不会被复制,但IE有bug,会复制事件处理程序,所以复制之前最好把事情处理程序去掉
        var cloneList = ulList.cloneNode(true);
        console.log(cloneList);
        //注意的是,cloneNode完之后必须要为它指定父节点,不然它无法显示
        div1.appendChild(cloneList);
    
    • normalize
      这个方法唯一的作用就是处理文档树中的文本节点。 由于解析器的实现或 DOM 操作等原因,可能会出现文本节点不包含文本,或者接连出现两个文本节点 的情况。当在某个节点上调用这个方法时,就会在该节点的后代节点中查找上述两种情况。如果找到了 空文本节点,则删除它;如果找到相邻的文本节点,则将它们合并为一个文本节点。

    2.Document类型

    在浏览器中,document对象是window的属性,可以直接访问.而document对象是HTMLDocument类型的实例(HTMLDocument类型继承自Document类型),document对象表示整个文档。

    • 2.1文档的子节点
        console.log(document);
        //为9
        console.log(document.nodeType);
        //为:#document
        console.log(document.nodeName);
        //为null
        console.log(document.nodeValue);
        //为null
        console.log(document.parentNode);
        //为null
        console.log(document.ownerDocument);
        //打印子节点:子节点可能有DocumentType,Element,ProcessingIn-struction,Comment.
        //兼容性的问题是不同浏览器对于出现在<html></html>以外的注释Comment是否加入到document的子节点中不一致
        console.log(document.childNodes);
        var docuChild = document.childNodes;
        for(var i=0,len=docuChild.length;i<len;i++){
            console.log(docuChild[i].nodeType);
        }
        //各浏览器对于doctype的支持不一致
        console.log(document.doctype);
        //常用的话是document的以下属性:
        //documentElement指向<html>元素
        console.log(document.documentElement);
        //指向<body>元素
        console.log(document.body);
    
    • 2.2文档信息
    //有一些属性是Document类型没有,是HTMLDocument类型才有的属性:
        //标题
        console.log(document.title);
        //可以修改文档标题
        document.title = 'bom学习';
        //URL:完整URL地址,domain:域名,referrer:来源页面的URL(如果没有就是空字符串)
        console.log(document.URL);
        console.log(document.domain);
        console.log(document.referrer);
        //可以设置domain:当页面中包含来自其他子域的框架或内嵌框架时,能够设置document.domain就非常方便了。
        //由于跨域安全限制,来自不同子域的页面无法通过 JavaScript 通信。
        //而通过将每个页面的 document.domain 设置为相同的值,
        //这些页面就可以互相访问对方包含的 JavaScript 对象了
        //不能将这个属性设置为URL中不包含的域
        //假设页面来自 p2p.wrox.com 域
        document.domain = "wrox.com"; // 成功
        document.domain = "nczonline.net"; // 出错!
        //浏览器对domain属性还有一个限制,即如果域名一开始是“松散的”(loose),那么不能将它再设置为“紧绷的”(tight)
        //假设页面来自于 p2p.wrox.com 域
        document.domain = "wrox.com"; //松散的(成功)
        document.domain = "p2p.wrox.com"; //紧绷的(出错!)
    
    • 2.3查找元素
      • getElementById():返回文档中指定id特性的元素,只返回文档中第一次出现指定id的元素。兼容性:①IE8 及较低版本不区分 ID 的大小写,其他浏览器都会区分;②IE7及更低版本:name 特性与给定 ID 匹配的表单元素(<input>、 <textarea>、<button>及<select>)也会被该方法返回(所以要避免name跟id相同的值)。
      • getElementsByTagName():返回的是包含零或多个元素的 NodeList,在 HTML 文档中,这个方法会返回一个 HTMLCollection 对象。
       //将HTMLCollection对象保存在lis变量中
       var imgs = document.getElementsByTagName('img');
       console.log(imgs);
       //获取其中某个元素:①item()方法
       console.log(imgs.item(0));
       //②类似数组传个index:底层调用了item()方法
       console.log(imgs[0]);
       //③使用这个方法可以通过元素的name特性取得集合中的项
       console.log(imgs.namedItem('shop'));
       //④HTMLCollection 还支持按名称访问项:底层调用了namedItem()方法
       console.log(imgs["changephone"]);
       //如果传入*当做tagName的话,会返回所有的元素
       var allEles = document.getElementsByTagName("*");
    
    • getElementsByName():HTMLDocument类型才有的方法.
      这个方法会返回带有给定 name 特性的所有元素,也是HTMLCollectioin集合.
    html:
    <div>
        <input type="radio" name="fruit" id="apple" value="苹果">
        <label for="apple">苹果</label>
        <input type="radio" name="fruit" id="pear" value="雪梨">
        <label for="pear">雪梨</label>
        <input type="radio" name="fruit" id="banana" value="香蕉">
        <label for="banana">香蕉</label>
    </div>
    
    js:
        var radios = document.getElementsByName('fruit');
        console.log(radios);
    
    • 2.4特殊集合

    除了属性和方法,document 对象还有一些特殊的集合。这些集合都是 HTMLCollection 对象, 为访问文档常用的部分提供了快捷方式:

    html:
    <a>百度</a>
    <a href="http://piaoshu.org" name="piaoshu">漂书</a>
    <a href="http://taobao.com">淘宝</a>
    
    js:
        //包含文档中所有的<form>元素
        console.log(document.forms);
        //包含文档中所有的<img>元素
        console.log(document.images);
        //包含文档中所有带有name特性的<a>元素
        console.log(document.anchors);//1个
        //包含文档中所有带 href 特性的<a>元素
        console.log(document.links);//2个
        //包含文档中所有的<a>元素
        console.log(document.getElementsByTagName('a'));//3个
    
    • 2.5DOM一致性检测

    DOM分为多个级别,也包含多个部分,所以一致性检测有需要:

       //参数:要检测的 DOM 功能的名称及版本号,如果实现了就返回true
       console.log(document.implementation.hasFeature('HTML','2.0'));
    
    Snip20180125_31.png
    但hasFeature的返回有时会不准确(浏览器可能是返回了true但并未全部实现),所以大多数情况下推荐使用能力检测.
    • 2.6文档写入
        //文档写入:writeln和write的区别是writeln在写入之后加了一个'\n'符
        //还可以写入script文件等等,注意对"和/script的转义
        document.write("<strong>" + (new Date()).toLocaleString() + "</strong>");
        document.writeln("<img src='../../weixin/images/category@2x.png'>");
        document.write("<script type=\"text/javascript\" src=\"dom1.js\"><\/script>");
        //如果onload之中写入会覆盖文档的原有内容
        window.onload = function () {
            document.write('覆盖性写入');
        }
        //方法 open()和 close()分别用于打开和关闭网页的输出流
    

    3.Element类型

        var btn1 = document.getElementsByClassName('btn1')[0];
        //为1
        console.log(btn1.nodeType);
        //为null
        console.log(btn1.nodeValue);
        //BUTTON(是大写)
        console.log(btn1.nodeName);
        console.log(btn1.tagName);
        //要比较标签名的话直接转化为小写比较会有通用性(HTML和XML中)
        console.log(btn1.tagName.toLowerCase() == 'button');
    
    • 3.1 HTML元素

    HTML元素:用HTMLElement类型表示,不是直接通过这个类型,也是通过它的子类型来表示,如HTMLDivElement,HTMLButtonElement,HTMLImageElement等等.HTMLElement直接继承自Element类型并添加了一些属性:①id:元素在文档中的唯一标识符,②className:与元素的class特性对应,③title:有关元素的附加说明信息,一般通过工具提示条显示出来,④lang:元素内容的语言代码,很少使用,⑤dir:语言的方向,ltr左到右,rtl右到左,很少使用.

    获取属性:

        var btn1 = document.getElementById('btn1');
        console.log(btn1.id);
        console.log(btn1.className);
        console.log(btn1.title);
        console.log(btn1.lang);
        console.log(btn1.dir);
        console.log(btn1.onclick);
        console.log(btn1.style);
    

    设置属性:

        btn1.id = 'newBtn1';
        btn1.title = '设置的title属性';
    
    • 3.2取得特性

    getAttribute()方法:参数是特性名称.而特性并不等于属性,这里做一个分类:

    • ①:公认特性(标准特性):就是指上面所述的.标准特性的特点:BOM对象会为标准特性创建相应名称的属性(class例外,对应属性名称是className,因为class是关键词).访问属性和特性获取到的内容一样,有两个特殊:onclick和style,属性返回对象,特性返回字符串(IE7及更早版本除外,特性也返回对象)
        var btn1 = document.getElementById('btn1');
        console.log(btn1.getAttribute('id'));
        console.log(btn1.getAttribute('title'));
        console.log(btn1.getAttribute('class'));
        console.log(btn1.getAttribute('onclick'));
        console.log(btn1.getAttribute('style'));
    
    • 自定义特性(特性名称不区分大小写)(自定义特性一般加data-前缀):对应自定义特性,只有IE才会把它以属性的形式添加到DOM对象,其他浏览器则不会,一般使用getAttribute()获取
    console.log(btn1.getAttribute('data-index'));
    

    所以总结起来就是:以编程的方式操纵DOM时,常使用对象的属性,对于自定义特性才使用getAttribute().

    • 3.3设置特性
        //设置特性:
        btn1.setAttribute('id','myBtn1');
        console.log(btn1.id);
        btn1.setAttribute('data-index','40');
        console.log(btn1.getAttribute('data-index'));
        //建议:除了设置自定义特性以外,都建议通过设置属性来设置特性,方便明了.
    

    removeAttribute():用于彻底删除元素的特性,调用这个方 法不仅会清除特性的值,而且也会从元素中完全删除特性,这个方法并不常用,但在序列化 DOM 元素时,可以通过它来确切地指定要包含哪些特性。

    • 3.4属性attributes

    attributes属性:Element类型是使用attributes属性的唯一一个DOM节点类型,attributes属性中包含一个NamedNodeMap,与NodeList类似,也是一个“动态”的集合,元素的每一个特性都由一个Attr节点表示,每个节点都保存在NamedNodeMap对象中.

        var btn1 = document.getElementById('btn1'),attrs = btn1.attributes;
        console.log(attrs);
        for(var i=0,len=attrs.length;i<len;i++){
            console.log(attrs[i].nodeType);
            console.log(attrs[i].nodeValue);
        }
    

    attributes作为NamedNodeMap,有以下方法:①getNamedItem:返回特定nodeName的节点,②removeNamedItem:移除特定nodeName的节点,③setNamedItem(node):向列表中添加节点,④item(pos):返回位于数字pos位置的节点.

        console.log(attrs.getNamedItem('class'));
        console.log(attrs.getNamedItem('data-index'));
        console.log(attrs.item(3));
        //方括号访问:
        console.log(attrs["id"]);
        //赋值
        attrs["id"].nodeValue = 'myBtn';
    

    一般取特性,给特性赋值都很少使用attributes,直接使用getAttribute(),setAttribute()更方便,一般用于遍历特性:

        function outputAttributes(element) {
            var pairs = [],
                    attrName,
                    attrValue,
                    i,
                    len;
            for (i = 0, len = element.attributes.length; i < len; i++) {
                attrName = element.attributes[i].nodeName;
                attrValue = element.attributes[i].nodeValue;
                if (element.attributes[i].specified) {
                    pairs.push(attrName + "=\"" + attrValue + "\"");
                }
            }
            return pairs.join(" ");
        }
      说明:每个特性节点都有一个名为specified的属性,这个属性的值如果      为 true,
      则意味着要么是在HTML中指定了相应特性,
      要么是通过setAttribute()方法设置了该特性.
      这里针对的是IE7及更早版本的问题:IE7及更早的版本会返回HTML元    素中所有可能的特性,
      包括没有指定的特性.
    
    • 3.5创建元素
        //创建元素
        var div = document.createElement("div");
        console.log(div.ownerDocument == document);
        //在IE中可以以另一种方式使用createElement(),即为这个方法传入完整的元素标签,也可以包含属性:
        var div1 = document.createElement("<div id=\"myNewDiv\" class=\"box\"></div >");
        //这种方式有助于避开在 IE7 及更早版本中动态创建元素的某些问题(在此不做列举),其他浏览器都不支持这种用法
    
    • 3.6元素的子节点

    元素的子节点:子节点有可能是元素、文本节点、注释或处理指令.不同浏览器对于看待子节点有不同:

    html:
    <ul class="ul-list">
        <li>第一行</li>
        <li>第二行</li>
        <li>第三行</li>
    </ul>
    js:
    var ulList = document.getElementsByClassName('ul-list')[0];
    console.log(ulList.childNodes);
    

    如果是 IE 来解析这些代码,ul有3个子节点,其他浏览器解析的话有7个,包括了4个text节点.如果将元素间的空白符删除,将返回相同数量的子节点.
    元素也支持 getElementsByTagName() 方法,探索的起点是当前元素.

    4.Text类型

    nodeType是3,nodeName是 #text ,nodeValue/data是节点所包含的文本:

        var text = document.getElementsByClassName('text-con')[0].firstChild;
        console.log(text.nodeType);
        console.log(text.nodeName);
        console.log(text.nodeValue);
    

    操作方法:除了以下的,还有splitText(),substringData():

        text.nodeValue = "修改的文本";
        console.log(text.nodeValue);
        text.appendData('我是新增加进来的文本');
        text.insertData(3,'插入的文本');
        text.deleteData(0,3);
        text.replaceData(0,3,'我是替代进来的文本');
        console.log(text.length);
    
    • 4.1创建文本节点
        var element = document.createElement("div");
        element.className = "message";
        var textNode = document.createTextNode("我是文本");
        element.appendChild(textNode);
        var anotherTextNode = document.createTextNode("我是另外的文本");
        element.appendChild(anotherTextNode);
        document.body.appendChild(element);
        //这种情况下两个节点中的文本就会连起来显示,中间不会有空格,因为两个文本节点是同胞节点.
    
    • 4.2规范化文本节点

    规范化就是把相邻的文本节点合并成一个文本节点:

        接上:
        console.log(element.childNodes);//打印2个文本节点
        element.normalize();//规范化
        console.log(element.childNodes);//打印1个文本节点
    
    • 4.3分割文本节点

    在指定位置把一个文本节点分割开2个文本节点:

        element.firstChild.splitText(5);
        //第一个是"我是文本我"(从0开始,5之前结束),第二个是"是另外的文本"
        console.log(element.childNodes);
    

    5.Comment类型

    Comment即注释:nodeType为8,nodeName为#comment,nodeValue/data是注释的内容.Comment 类型与 Text 类型继承自相同的基类,因此它拥有除 splitText()之外的所有字符串操作方法:

        var div = document.getElementsByClassName('div-con')[0];
        div.append(document.createComment('我是DOM添加的注释内容啊'));
    

    6.CDATASection类型

    CDATASection 类型只针对基于 XML 的文档,表示的是 CDATA 区域。与 Comment 类似, CDATASection 类型继承自 Text 类型,因此拥有除 splitText()之外的所有字符串操作方法。

    • nodeType为4
    • nodeName为#cdata-section
    • nodeValue是是 CDATA 区域中的内容

    7.DocumentType类型

    DocumentType 类型在 Web 浏览器中并不常用,仅有 Firefox、Safari 和 Opera 和部分chrome支持它.

    • nodeType为0
    • nodeName的值为 doctype 的名称
    • nodeValue 的值为 null
    • parentNode 是 Document

    在 DOM1 级中,DocumentType 对象不能动态创建,而只能通过解析文档代码的方式来创建。支持它的浏览器会把 DocumentType 对象保存在 document.doctype 中。
    DOM1 级描述了 DocumentType 对象的 3 个属性:name、entities 和 notations。其中,name 表示文档类型的名称; entities 是由文档类型描述的实体的 NamedNodeMap 对象;notations 是由文档类型描述的符号的 NamedNodeMap 对象。通常,浏览器中的文档使用的都是 HTML 或 XHTML 文档类型,因而 entities 和 notations 都是空列表(列表中的项来自行内文档类型声明).
    所以,只有 name 属性是有用的。这个属性中保存的是文档类型的名称,也就是出现在<!DOCTYPE 之后的文本。

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
      "http://www.w3.org/TR/html4/strict.dtd">
    //DocumentType 的 name 属性中保存的就是html
    

    IE 及更早版本不支持 DocumentType,因此 document.doctype 的值始终都等于 null。可是, 这些浏览器会把文档类型声明错误地解释为注释,并且为它创建一个注释节点。IE9 会给 document.doctype 赋正确的对象,但仍然不支持访问 DocumentType 类型。

    8.DocumentFragment类型

    在所有节点类型中,只有 DocumentFragment 在文档中没有对应的标记。DOM 规定文档片段是一种“轻量级”的文档,可以包含和控制节点,但不会像完整的文档那样占用额外的资源。

    • nodeType为11
    • nodeName 的值为"#document-fragment"
    • nodeValue为null
    • parentNode为null
    • 子节点可以是Element、ProcessingInstruction、Comment、Text、CDATASection 或EntityReference.
      文档片段继承了 Node 的所有方法,通常用于执行那些针对文档的 DOM 操作。常用document fragment当做仓库使用,避免多次渲染和布局文档:
        var fragment = document.createDocumentFragment(),ul = document.getElementById('temp-ul');
        var li = null;
        for(var i=0;i<3;i++){
            li = document.createElement('li');
            li.append(document.createTextNode('我是新创建的第'+i+'个li'));
            fragment.append(li);
        }
        ul.append(fragment);
    

    9.Attr类型

    特性节点就是存在于元素的 attributes 属性中的节点:

    • nodeType是2
    • nodeName 的值是特性的名称
    • nodeValue 的值是特性的值
    • parentNode 的值为 null
    • 在 HTML 中不支持(没有)子节点,在 XML 中子节点可以是 Text 或 EntityReference

    尽管它们也是节点,但特性却不被认为是 DOM 文档树的一部分。我们最常使用的是 getAttribute()、setAttribute()和 remveAttribute()方法,很少直接引用特性节点。
    Attr 对象有 3 个属性:name、value 和 specified。其中,name 是特性名称(与nodeName的值相同),value 是特性的值(与nodeValue的值相同),而 specified是一个布尔值,用以区别特性是在代码中指定的,还是默认的。
    创建Attr和赋给元素使用:document.createAttribute和ele.setAttributeNode.

    相关文章

      网友评论

        本文标题:dom总结:节点层次

        本文链接:https://www.haomeiwen.com/subject/nrfxaxtx.html