慕课网 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的支持:
- 常用节点类型: nodeType
- nodeName 节点名称,nodeValue 节点值,attributes 获取属性
```
<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标签解析编程DOM节点。
渲染引擎的渲染流程
- 渲染:浏览器把请求到的HTML内容显示出来的过程。
- 渲染引擎首先通过网络获得所请求文档的内容,通常以8k分块的方法来完成。
- 之后的过程:(不包含浏览器加载外部资源的过程,如图片、脚本)
1.解析HTML,构建DOM树(构建DOM节点)。
2.构建渲染树(解析样式信息,包括外部的css文件、style标签中的样式)。渲染树由一些包含有各种属性的矩形组成,他们将会按照正确的顺序显 示到屏幕上。
3.布局渲染树(布局DOM节点),执行布局的过程,将确定每个节点在屏幕上的确切坐标。
4.绘制渲染树(绘制DOM节点,即遍历渲染树),使用UI后端层来绘制每个节点。
- 之后的过程:(不包含浏览器加载外部资源的过程,如图片、脚本)
- Webkit主要渲染流程:
- 拓展阅读浏览器内部工作原理
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是十分耗性能的 。
-
创建一个文本,要追溯6层:
a82d56ad-ff35-454f-a0fc-923bb3ed43d0.png - 只是第一层的属性就有这么多,可见多用DOM会有多卡:
HTML嵌套规则
-
HTML嵌套规则:HTML存在许多种类型的标签,有的标签下只允许特定的标签存在,这就叫HTML嵌套规则。
- 不按HTML嵌套规则写,浏览器就不会正确解析,会将不符合嵌套规则的节点放到目标节点的下面,或者变为纯文本。
- 块状元素和内联元素:
- 块状元素和内联元素嵌套规则:
- 某些特殊元素嵌套规则:
网友评论