美文网首页
《DOM探索之基础详解篇》笔记

《DOM探索之基础详解篇》笔记

作者: 8eeb5fce5842 | 来源:发表于2016-03-03 20:34 被阅读418次

慕课网 DOM探索之基础详解篇 学习笔记

一、认识DOM

  • DOM 提供了用程序来动态控制HTML的接口。
  • DOM级别:
    • DOM 0级:实际上是不存在的,只是DOM历史坐标系的一个参照点而已,多指DHTML。
    • DOM 1级:DOM core,DOM HTML.
    • DOM 2级:DOM Views,DOM Events,DOM Style,DOM Traversal and Range.
    • DOM 3级:DOM Load And Save,DOM Validation.
  • Web浏览器对DOM的支持:
3c49055b-1b1b-4a25-91d3-db3cdd20e2cc.png
  • 常用节点类型: nodeType
c71689c8-5e78-4e79-8c9e-af32fcc2c210.png
  • nodeName 节点名称,nodeValue 节点值,attributes 获取属性
8592f28b-e69c-47b6-8f43-5a961bf34685.png

```
<body>

<div id="container">这是一个元素节点</div>
<script>
var divNode = document.getElementById('container'); // 元素节点
console.log(divNode.nodeName + '/' + divNode.nodeValue);
// DIV/null

var attrNode = divNode.attributes[0]; // 属性节点
console.log(attrNode.nodeName + '/' + attrNode.nodeValue);
// id/container

var textNode = divNode.childNodes[0]; // 文本节点
console.log(textNode.nodeName + '/' + textNode.nodeValue);
// #text/这是一个元素节点

var commentNode = document.body.childNodes[1]; // 注释节点
console.log(commentNode.nodeName + '/' + commentNode.nodeValue);
// #comment/nodeName,nodeValue 实验

var docNode = document.doctype; // 文档节点
console.log(docNode.nodeName + '/' + docNode.nodeValue);
// html/null

var fragNode = document.createDocumentFragment(); // 文档片段节点
console.log(fragNode.nodeName + '/' + fragNode.nodeValue);
// #document-fragment/null
</script>
</body>
```

二、DOM Ready

  • 页面加载时,有一个DOM节点构建的过程,当页面上所有的HTML都转换成了节点以后,就叫做DOM Ready(DOM树构建完毕)。
    • 浏览器通过渲染引擎将HTML标签解析编程DOM节点。
      • 渲染引擎的职责是:把请求到的内容显示到浏览器屏幕上。默认情况下渲染引擎可显示HTML、XML文档及图片。通过插件,其可显示其他类型的文档,如PDF等。

渲染引擎的渲染流程

  • 渲染:浏览器把请求到的HTML内容显示出来的过程。
  • 渲染引擎首先通过网络获得所请求文档的内容,通常以8k分块的方法来完成。
    • 之后的过程:(不包含浏览器加载外部资源的过程,如图片、脚本)
      1.解析HTML,构建DOM树(构建DOM节点)。
      2.构建渲染树(解析样式信息,包括外部的css文件、style标签中的样式)。渲染树由一些包含有各种属性的矩形组成,他们将会按照正确的顺序显 示到屏幕上。
      3.布局渲染树(布局DOM节点),执行布局的过程,将确定每个节点在屏幕上的确切坐标。
      4.绘制渲染树(绘制DOM节点,即遍历渲染树),使用UI后端层来绘制每个节点。
9c5c9a80-c81a-4265-b784-f9d192a937a0.png
  • Webkit主要渲染流程:
09de489c-0b25-4bde-af92-09746975f930.png
- 拓展阅读浏览器内部工作原理

DOM Ready 的实现策略

54589b7c-179c-4f90-9b6e-a54a56ea920b.png
  • window.onload会完整加载页面后在触发。这些策略是DOM树加载完成就触发,无需等待其他东西的加载。
  • JQ就是这样的。
  • 自己来实现一个在标准和非标下模拟DOMContentLoaded的功能:
    function myReady(fn){
    //对于现代浏览器,对DOMContentLoaded事件的处理采用标准的事件绑定方式
    if ( document.addEventListener ) {
        document.addEventListener("DOMContentLoaded", fn, false);
    } else {
        IEContentLoaded(fn);
    }
    //IE模拟DOMContentLoaded
    function IEContentLoaded(fn) {
        var d = window.document;
        var done = false;
        //只执行一次用户的回调函数init()
        var init = function () {
            if (!done) {
                done = true;
                fn();
            }
        };
        (function () {
            try {
                // DOM树未创建完之前调用doScroll会抛出错误
                d.documentElement.doScroll('left');
            } catch (e) {
                //延迟再试一次~
                setTimeout(arguments.callee, 50);
                return;
            }
            // 没有错误就表示DOM树创建完毕,然后立马执行用户回调
            init();
        })();
        //监听document的加载状态
        d.onreadystatechange = function() {
            // 如果用户是在domReady之后绑定的函数,就立马执行
            if (d.readyState == 'complete') {
                d.onreadystatechange = null;
                init();
            }
        }
    }
    

}
```

  • 对比:
    var d = document;
      var msgBox = d.getElementById("showMsg");
      var imgs = d.getElementsByTagName("img");
      var time1 = null, time2 = null;
      myReady(function(){
          msgBox.innerHTML += "dom已加载!<br>";
          time1 = new Date().getTime();
          msgBox.innerHTML += "时间戳:" + time1 + "<br>";
      });
      window.onload = function(){
          msgBox.innerHTML += "onload已加载!<br>";
          time2 = new Date().getTime();
          msgBox.innerHTML += "时间戳:" + time2 + "<br>";
          msgBox.innerHTML +="domReady比onload快:" + (time2 - time1) + "ms<br>";
    

三、判断元素的节点类型

  • 判定方法:
    • isElement:判断是否为元素节点。
    • isHTML:判断是否为HTML文档的元素节点。
    • isXML:判断是否为XML文档的元素节点。
    • contains:判断两个节点的包含关系。

判断节点为元素节点 isElement

  • 简单版:
var isElement = function (el){
            return !!el && el.nodeType === 1;
        }
  • 完美版:
var isElement = function (obj) {
            if (obj && obj.nodeType === 1) {//先过滤最简单的
                if( window.Node && (obj instanceof Node )){ //如果是IE9,则判定其是否Node的实例
                    return true; //由于obj可能是来自另一个文档对象,因此不能轻易返回false
                }
                try {//最后以这种效率非常差但肯定可行的方案进行判定
                    testDiv.appendChild(obj);  // 不是元素节点,不能执行该步
                    testDiv.removeChild(obj);
                } catch (e) {
                    return false;
                }
                return true;
            }
            return false;
        }

判断节点为HTML和XML元素节点 isHTML isXML

  • HTML是XML的子集。
  • isXML:
    // Sizzle, jQuery自带的选择器引擎
        var isXML = function(elem) {
            var documentElement = elem && (elem.ownerDocument || elem).documentElement;
            return documentElement ? documentElement.nodeName !== "HTML" : false;
        };
        console.log(isXML(document.getElementById("test"))); // false
    
        // 但这样不严谨,因为XML的根节点,也可能是HTML标签,比如这样创建一个XML文档
        try {
            var doc = document.implementation.createDocument(null, 'HTML', null);
            console.log(doc.documentElement);
            console.log(isXML(doc));
        } catch (e) {
            console.log("不支持creatDocument方法");
        }
    
    // mootools的slick选择器引擎的源码:
        var isXML = function(document) {
            return (!!document.xmlVersion) || (!!document.xml) || (toString.call(document) == '[object XMLDocument]')
                    || (document.nodeType == 9 && document.documentElement.nodeName != 'HTML');
        };
    
        // 精简版
        var isXML = window.HTMLDocument ? function(doc) {
            return !(doc instanceof HTMLDocument);
        } : function(doc) {
            return "selectNodes" in doc;
        }
    
    • 用功能判断来实现:(佳)
    var isXML = function(doc) {
            return doc.createElement("p").nodeName !== doc.createElement("P").nodeName;
        }
    
  • isHTML:
    var isHTML = function(doc) {
            return doc.createElement("p").nodeName === doc.createElement("P").nodeName;
        }
    
    • isHTMLElement:
    var isElement = function (obj) {
            if (obj && obj.nodeType === 1) {//先过滤最简单的
                if( window.Node && (obj instanceof Node )){ //如果是IE9,则判定其是否Node的实例
                    return true; //由于obj可能是来自另一个文档对象,因此不能轻易返回false
                }
                try {//最后以这种效率非常差但肯定可行的方案进行判定
                    testDiv.appendChild(obj);
                    testDiv.removeChild(obj);
                } catch (e) {
                    return false;
                }
                return true;
            }
            return false;
        }
        var isHTMLElement(el){
           if(isElement){
              return isXML(el.ownerDocument);
           }
           return false;
        }
    

判断节点的包含关系 contains

  • 目前几乎所以浏览器都支持contains方法:
<body>
    <div id="p-node">
        <div id="c-node">子节点内容</div>
    </div>
    <script>
        var pNode = document.getElementById("p-node");
        var cNode = document.getElementById("c-node").childNodes[0];
        alert(document.contains(cNode)); // Chrome:true IE:报错 因为IE的docuemnt下无contains方法
        alert(pNode.contains(cNode)); // Chrome:true IE:报错 因为IE下不能用contains判断文本节点
        // 只有判断元素节点时才全兼容,弹true
    </script>
</body>
  • 自写全兼容版本方法:
    function fixContains(a, b) {
            try {
                while ((b = b.parentNode)){ // 找到内层节点的父节点,找不到便停止
                    if (b === a){ // b现在是父节点,若等于a,则说明a为父节点
                        return true;
                    }
                }
                return false;
            } catch (e) {
                return false;
            }
        }
    

四、继承层次与嵌套规则

DOM节点继承层次

  • 创建一个p元素,一共追溯了7层原型链,可见DOM是十分耗性能的 。
b2fbb735-0e38-499f-b14f-e3ebd4a6d97e.png
  • 创建一个文本,要追溯6层:


    a82d56ad-ff35-454f-a0fc-923bb3ed43d0.png
  • 只是第一层的属性就有这么多,可见多用DOM会有多卡:
2f545974-67f5-4563-8bfe-755b7c003c48.png

HTML嵌套规则

  • HTML嵌套规则:HTML存在许多种类型的标签,有的标签下只允许特定的标签存在,这就叫HTML嵌套规则。
    • 不按HTML嵌套规则写,浏览器就不会正确解析,会将不符合嵌套规则的节点放到目标节点的下面,或者变为纯文本。
  • 块状元素和内联元素:
ebb804c4-878f-459d-8f9f-a2171c5f8235.png 0d8a5912-d889-48ff-9ec9-6c4956581d51.png
  • 块状元素和内联元素嵌套规则:
7b392fa5-1333-429f-af87-4a50be5be8d8.png 51064f6d-f23b-475b-9920-0681b3949049.png 69d68339-4832-455a-a3e1-5437cd2f659c.png c781fd87-d163-44d0-9535-7ff23fc35d4d.png 1a0cec79-cfb9-4d2b-bab8-28a4a2eb95cb.png
  • 某些特殊元素嵌套规则:
04bc252f-b64c-4978-98fd-c2a4db902499.png 901f826b-01a7-46aa-94bc-ea83f6628e35.png 1e005ac5-1308-42a5-8702-7a271c3d7aa4.png 14b6c0bd-1d59-48c2-8242-5c9d3fc7f531.png 951be6f6-e5e9-42c5-b391-cd826ba1d13a.png

相关文章

网友评论

      本文标题:《DOM探索之基础详解篇》笔记

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