10|DOM

作者: 井润 | 来源:发表于2019-12-20 23:23 被阅读0次

    什么是DOM?

    • Document Object Model文档对象模型
    • 针对HTML和XML文档的一个API(Application Programming Interface)
    • 描绘了一个层次化的节点树,允许开发人员进行增删改页面的某一部分!
    • 脱胎于NetScape及微软公司的DHTML(Dynamic HTML)

    对应的发展历程?

    • 1998年DOM 1级规范成为W3C推荐标准,为文档结构及查询提供了接口,主要是定了HTML和XML文档的底层结构
    • DOM2在DOM1的基础上引入了更多的交互能力!
    • DOM3引入了以统一方式加载和保存文档的方法!

    01|节点层次

    DOM可以将任何HTML或者说XML文档庙会成为一个由多层节点构成的结构!

    • 节点分为不同的类型,每种类型分别表示文档中不同的信息或者说标记!
    • 每次节点都有自己的特点,数据和方法!

    对应的文档节点只有一个子节点,也就是所谓的<html>元素,我们又称之为"文档元素",文档中的所有元素都包含在这个文档元素之中!

    对应的每个文档只能够有一个文档元素!

    • HTML中文档元素始终都是<html>
    • XML中没有预定义的文档元素!

    02|Node类型

    DOM1级定义了一个Node接口,该接口由DOM中的所有节点类型实现! Node接口在JavaScript中是作为Node类型实现的!

    • 其他所有的浏览器(除了IE)都能访问到这个类型,JavaScript中的所有节点都继承自Node类型! 对应的所有节点类型都共享着相同的基本属性和方法
    • 对应的每个节点都有其对应的nodeType属性,用于表明节点的类型!

    节点类型由node类型中定义的12个数值常量进行表示:

    1. Node.ELEMENT_NODE(1); 元素节点
    2. Node.ATTRIBUTE_NODE(2);
    3. Node.TEXT_NODE(3); Element或者说Attr中实际的文字
    4. Node.CDATA_SECTION_NODE(4); 一个CDATASection 例如说:<!CDATA[[...]]>
    5. Node.ENTITY_REFERENCE_NODE(5);
    6. Node.ENTITY_NODE(6);
    7. Node.PROCESSING_INSTRUCTION_NODE(7); 一个用于XML文档的ProcessingInstruction(处理指令)
    8. Node.COMMENT_NODE(8); 一个注释节点
    9. Node.DOCUMENT_NODE(9); 一个文档节点
    10. Node.DOCUMENT_TYPE_NODE(10); 描述文档的DocumentType节点
    11. Node.DOCUMENT_FRAGMENT_NODE(11); 文档片段
    12. Node.NOTATION_NODE(12);

    任何的节点必定是这其中的一种!

    对应的被弃用的节点类型常量:

    常量 描述
    Node.ATTRIBUTE_NODE 2 元素 的耦合属性 。在 DOM4 规范里Node 接口将不再实现这个元素属性。
    Node.ENTITY_REFERENCE_NODE 5 一个 XML 实体引用节点。 在 DOM4 规范里被移除。
    Node.ENTITY_NODE 6 一个 XML <!ENTITY ...> 节点。 在 DOM4 规范中被移除。
    Node.NOTATION_NODE 12 一个 XML <!NOTATION ...> 节点。 在 DOM4 规范里被移除.

    其中有些时候可以利用nodeType与常量进行比较,例如someNode.nodeType===NODE>ELEMENT_NODE相等的话对应的意味着someNode确实是一个元素!

    这种情况适用于特定浏览器的使用,但是如果说需要保持兼容的话,可以直接和数字进行比较:

    if(someNode.nodeType === 1){
        console.log("node is an element!")
    }
    

    其中介绍到了nodeName和nodeValue的属性,两个属性的值完全取决于节点的类型

    • 如果是元素的话,取得并且保存nodeName的值 始终保存的是元素的标签名 nodevalue保存的值始终为null

    其中对应的节点关系,其实可以使用传统的家族关系来进行表示!

    每个节点都有一个childNodes,其中保存这一个NodeList对象,NodeList是一种类数组,用于保存着一组有序的节点,可以通过位置访问这些节点! NodeList对象最奇特的地方在于,它实际上是基于DOM结构动态执行查询的结果,DOM结构的动态变化会自动反映在NodeList对象中!

    IE8及更早的版本将NodeList实现为一个COM对象,我们不能够像JavaScript对象中那种对象,需要将NodeList转换为数组:

    const convertArray = nodes=>{
        let array = null;
        try{
            array = [].slice.call(nodes,0);
        }catch(excepion{
            array = [];
            for(let i=0;i<nodes.length;i++){
                array.push(nodes[i]);
            }
        }
        return array;
    }
    

    对应的每一个节点都parentNode属性,该属性指向文档书中的父节点,包含在childNodes列表中的所有节点都具有相同的父节点! 因此对应的parentNode属性都指向同一个节点!

    其中对应的两个API是访问对应的兄弟节点:

    • previousSibling
    • nextSibling

    对应的一个父节点的 firstChildlastChild分别指向NodeList中的第一个和最后一个节点!

    • 父节点只有一个子节点,那么对应的firstChildlastChild都为同一个节点
    • 如果说没有子节点,那么对应的firstChild和lastChild的值均为null!

    其中有一个API可以很好地判断该节点的子节点是否存在! 如果子节点的数量为1或者更多的时候,那么就返回true!

    对应的方法为:hasChildNodes

    最后的一个属性就是ownerDocument可以指向整个文档的文档节点!

    操作节点

    DOM提供了一系列操作节点的方法,其中最最最常用的就属于appendChild方法了,用于向childNodes中添加一个节点!此时添加的节点就属于childNodes中的最后一个节点了!

    如果说需要把特定的节点放到childNodes的某个节点之后就需要使用下面的API了:

    • insertBefore
    someNode.insertBefore(node,currentNode);//node:插入的节点 currentNode:表示参照的节点
    someNode.insertBefore(node,null);//someNode的childNodes的最后位置添加一个节点node
    someNode.insertBefore(node,someNode.firstChild);//插入到第一个节点的前面 作为第一个节点
    someNode.insertBefore(node,someNode.lastChild);//插入到第最后节点的后面 作为最后的节点
    
    • replaceChild
    someNode.replaceChild(insertNode,replaceNode);//insertNode:插入的节点 replaceNode:替换的Node 返回被替换掉的节点
    someNode.replaceChild(newNode,someNode.firstChild);//替换第一个节点
    someNode.replaceChild(newNode,someNode.lastChild);//替换最后一个节点
    
    • removeChild
    someNode.removeChild(node);//移除指定的节点 并且被移除的节点成为返回值
    someNode.removeChild(someNode.firstChild);//删除第一个子节点
    someNode.removeChild(someNode.lastChild);//删除最后一个子节点
    

    其他的方法有一个方法叫做cloneNode作为克隆节点的方法,接受一个布尔类型的参数,如果说为true的话进行深克隆,复制整个节点和对应的子节点数,如果说为false的话,对应的复制节点本身!

    对应的,cloneNode方法不会复制DOM节点中的JavaScript属性,例如说事件处理程序等等! 其他一切都不会复制,IE再次存在一个Bug,他会复制事件的处理程序,因此在使用该方法之前最好是先移除对应的事件处理程序!

    02|Document类型

    对应的JavaScript通过Document雷星表示文档,document对象是HTMLDocument的一个实例,表示整个HTML页面,并且document是window对象的一个属性!

    对应的Document类型可以表示HTML页面或者说基于XML的文档,最最最常见的还是作为HTMLDocument实例的document对象!

    • 该对象可以去的页面相关信息
    • 操作页面的外观及其对应的底层结构!
    1. 文档的子节点

    对应的DOM标准规定了Document的子节点可以是:

    • DocumentType
    • Element
    • ProcessingInstruction
    • Comment

    但是对应的内置了两个可以访问子节点的方式如下所示:

    • 通过documentElement
    • 通过childNodes列表访问子节点

    经常写HTML的人应该不陌生,对应的HTML页面经过浏览器解析之后,其实很明显的就能够知道,文档中只包含一个子节点,html元素:

    下面是几种访问子节点的方式:

    let html = document.documentElement;
    console.log(html === document.childNodes[0]);
    console.log(html === document.firstChild);
    

    其实对应关系都是指向同一个字节点,HTML元素

    其实Document对象中还包含了很多属性的,例如说:

    • document.body //对应的可以直接访问body元素!
    • document.doctype //取得对 文档类型的引用! <!DOCTYPE>
    1. 文档信息的获取

    对应的文档信息中的内容通过document对象的属性进行获取或者说设置,那么第一个我们常见的就是所谓的标题:

    const title = document.title;
    document.title = "Hello ProbeDream";
    

    如果说是对应的url也是通过类似的方式进行获取或者说设置:

    const url = document.URL;
    document.URL = "https://github.com/probedream"
    

    如果说要想获取域名:

    const domain = document.domain;
    

    如果说想获取来源页面的URL:

    const referer = documnt.referer;
    
    1. 元素的获取

    我们就在书中所提到的API中将几个比较常见的API提炼出来:

    • document.getElementById(); //通过对应的id取得页面中对应ID的元素
    • document.getElementsByTagName(); // 通过对应的标签名获取到对应的 HTMLCollection (元素集合)

    对应的还有一个不怎么常见的API,叫做 namedItem 通过元素的name属性获取到元素集合中符合条件的元素!

    如果说想获取页面中的所有元素,可以使用我们介绍到的 getElementsByTagName() 传入对应的 "*" 拿到对应的所有元素! 集合中以顺序的方式拿到对应的元素!

    • 还有一个不常用的API,叫做 getElementByName 通过name属性拿到符合条件name的所有的元素集合!
    1. 特殊集合

    除了对应的属性和方法,document对象还提供了一些特殊的集合,对应的集合都是为 HTMLCollection对象

    本文中介绍到的也是快捷方式:

    1. document.anchors: 文档中所有带name特性的a元素
    2. document.forms: 文档中所有的form元素
    3. document.applet: 文档中所有的applet元素
    4. document.images: 文档中所有的img元素
    5. document.links: 文档中所有的具有href特性的a元素
    1. DOM一致性检测

    DOM分为不同的级别,也包含了多个部分,因此对应的检测浏览器实现了DOM的哪些部分还是比较重要的,对应的文档对象提供了一个API,叫做:document.implementation属性就是为此提供响应信息和功能的对象!

    dom1级值为document.implementation提供了一个方法,为: hasFeature 表是否拥有该特性/功能!

    1. 文档写入

    其实关于这一点: 文档写入的功能也是在看JS高程的时候才发现,不是常用的一个特性!

    对应的有四个API:

    • write 原样写入
    • writeln 字符串末尾加上对应的换行符
    • open 打开网页的输出流
    • close 关闭网页的输出流
    03|Element类型

    除了Document类型之外,Element类型就要算是Web编程中最常用的类型了,Element类型用于表现XML或者说HTML元素,提供了对元素的标签名,子节点及特性访问!

    如果说我们想要访问元素的标签名,可以使用两个属性,分别是:nodeName属性和对应的tagName属性会返回相同的值,但是明显后者更加符合语意!

    1. HTML元素

    所有的HTML元素都有HTMLElement类型表示,而不是直接通过该类型,也是通过该类型的子类型进行表示,HTMLElement类型直接继承来自Element并且添加了一些属性,元素中添加的属性,我们都可以通过元素对象的属性获取:

    <div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr"></div>
    <script>
        const div = document.getElementById("myDiv");
        console.log(`class属性:${div.class} title属性:${div.title} lang属性:${div.lang} dir属性:${div.ltr}`)
    </script>    
    
    1. 取得特性

    每个元素都会有一个或者说多个特性,这些特性的用途其实就是给元素附加信息,操作特性的DOM操作方法有三个:

    • getAttribute
    • setAttribute
    • removeAttribute

    其实通过对应的API的名称就能够很清楚的知道如何使用了!

    const div = document.getElementById("mydiv");
    div.getAttribute("message");
    div.getAttribute("attribute key","value");
    div.removeAttribute("message");
    

    对应的Element类型是使用attributes属性的唯一一个DOM节点类型,attributes属性中包含一个NamedNodeMap,与对应的NodeList相似,是一个动态的集合!

    • 元素的每一个特性都会有Attr节点进行表示
    • 每个节点都保存在NamedNodeMap对象中,NameNodeMap对象拥有下列方法
    1. getNamedItem(name) : 返回nodeName属性等于name的节点
    2. removeNamedItem(name): 从对应列表中移除nodeName属性等于name的节点
    3. setNamedItem(node) :向对应的列表中添加节点
    4. item(pos):返回位于数字position位置处的节点!
    1. 创建元素

    对应的常见元素,就需要使用到我们最常见的API:document.createElementAPI了 对应的里面传入的是对应的标签名,如果说是在HTML中的话标签名不分大小写,如果说是在XML中的话对应的严格区分大小写!

    04|Text类型

    对应的文本节点其实就是有Text类型予以表示,不包含对应的HTML代码,对应的就是文本内容!

    常用的API如下所示:

    1. createTextNode:创建文本节点! 传入要插入节点的文本!
    05|Comment类型

    对应的这就是所谓的注释类型了! 对应的开发中也很少用到! 我们做简单的了解不进行深入探讨了!

    最常用的API也就所属:createComment里面传入对应的注释内容!

    06|CDATASection类型

    对应的CDATASection类型指针对基于XML的文档,表示的是CDATA区域! 继承自Text类型!

    但是只会出现在XML文档中,HTML中并不会涉及,如果说涉及到XML的开发,可以使用document.createCDataSection创建对应的CDATA区域!

    07|DocumentType类型

    该类型在Web浏览器中并不常用,仅仅有Firefox,Safari,Opera中支持他!

    08|DocumentFragment类型

    其实从字面意思看出表示文档碎片的意思,是一种轻量级的文档,可以包含和控制节点,并不会向完整的文档那样占用额外的资源! 与此同时拥有Node的所有方法,通常用于执行那些针对文档的DOM操作!

    其中介绍到的API:createDocumentFragment

    09|Attr类型

    元素的特性在DOM中以Attr类型进行表示,技术角度而言的话就是存在于元素attributes属性中的节点!

    02|DOM操作技术

    01|动态脚本
    const loadScript = url=>{
        const script = document.createElement("script");
        script.type = "text/javascript";
        script.src = url;
        document.body.appendChild(script);
    }
    loadScript("client.js");//加载脚本
    

    但是对应的IE会出现问题,我们推出一个兼容性不错的方法:

    const loadScriptString = code=>{
        const script = document.createElement("script");
        script.type = "text/javascript";
        try{
            script.appendChild(document.createElement(code));    
        }catch(exception){
            script.text = code;
        }
        document.body.appendChild(script);
    }
    
    loadScriptString("const sayHi = ()=>{console.log('Hello!')}");
    
    02|动态样式
    const loadStyleString = css=>{ 
        const style = document.createElement("style"); 
        style.type = "text/css"; 
        try{ 
            style.appendChild(document.createTextNode(css)); 
        } catch (ex){ 
            style.styleSheet.cssText = css; 
        } 
        const head = document.getElementsByTagName("head")[0]; 
        head.appendChild(style); 
    }
    loadStyleString("body{background-color:red}");
    

    03|小结

    本文讲到的都是一些JavaScript中比较基础和关键的内容,之后的下一章会对其DOM内容作补充操作! 欢迎在评论区与我交流

    相关文章

      网友评论

          本文标题:10|DOM

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