DOM探索

01
Javascript的组成:
ECMAscript:描述了语言的语法和基本对象;
BOM:描述了与浏览器进行交互的方法和接口,如浏览器窗口、浏览器导航对象、浏览器分辨率、历史记录、cookie等等。

认识DOM

DOM:处理HTML文档,描述了处理网页内容的方法和接口;将HTML看成一个文档树

DOM级别

02
DOM1级主要定义了HTML和XML文档的底层结构。
在DOM1中,DOM由两个模块组成:DOM Core(DOM核心)和DOM HTML。

  • DOM Core规定了基于XML的文档结构标准,通过这个标准简化了对文档中任意部分的访问和操作。
  • DOM HTML则在DOM核心的基础上加以扩展,添加了针对HTML的对象和方法,如:JavaScript中的Document对象.

DOM2级在原来DOM的基础上又扩充了鼠标、用户界面事件、范围、遍历等细分模块,而且通过对象接口增加了对CSS的支持。DOM1级中的DOM核心模块也经过扩展开始支持XML命名空间。
在DOM2中引入了下列模块,在模块包含了众多新类型和新接口:

  • DOM视图(DOM Views):定义了跟踪不同文档视图的接口
  • DOM事件(DOM Events):定义了事件和事件处理的接口
  • DOM样式(DOM Style):定义了基于CSS为元素应用样式的接口
  • DOM遍历和范围(DOM Traversal and Range):定义了遍历和操作文档树的接口

DOM3进一步扩展了DOM,在DOM3中引入了以下模块:

  • 加载和保存模块(DOM Load and Save):引入了以统一方式加载和保存文档的方法
  • DOM验证模块(DOM Validation):定义了验证文档的方法
  • DOM核心的扩展(DOM Style):支持XML 1.0规范,涉及XML Infoset、XPath和XML Base

文档类型


HTML是根据标准HTML规范命名元素、标签、属性, 元素和属性作为标准能被所有浏览器解析;
xml是存放格式化数据的,里面的标签可以根据语义要求任意取名,无法被浏览器识别.

节点类型

节点类型共12种,其中常用的七种Element(元素节点),Attr(属性节点)Text(文本节点),Comment(注释节点),Document(文档节点),DocumentType(文档类型节点),DocumentFragment(文档片段节点)

■ 元素节点:

拥有子节点和文本,是唯一能拥有属性的节点类型

■ 属性节点:

元素中的属性,是附属于元素的,是包含他的元素节点的一部分,不属于文档树的一部分

■ 文本节点:

只包含文本内容(可以只包含空白)的节点,在xml中称为字符数据;
在文档树中元素的文本内容和属性的文本内容都是由文本节点表示的
某个节点的空白区域,也是属于文本节点

■ 注释节点:

表示注释的内容

■ 文档节点:

文档树的根节点,是其他节点的父节点;
注意不是html或者xml的根元素。根元素是作为文档节点的子节点出现的

整个代码之上看做是文档节点

■ 文档类型节点: 例;<!doctype html>

■ 文档片段节点:

文档片段是轻量级的或者是最小的Document对象,他表示文档的一部分或者是一段,他不属于文档树;
他的特殊行为:占位符,暂时存放一次插入文档的节点,同时有利于剪贴复制操作
DocumentFragment节点使用示例,DocumentFragment文本片段节点可以作为一个占位符,来保存其他需要一次性插入文档的节点,当将其插入到某个节点内时,只是插入其所有子孙节点,其本身不会被插入!

nodeType判断节点类型:
非ie中,可以使用字符串常量判断。divNode.nodeType == Node.ELEMENT_NODE。
ie中,由于没有Node对象,需使用数值判断。divNode.nodeType == 1(即元素节点的编号)。
因此:应使用数值常量来判断节点类型,以兼容所有浏览器。

节点的nodeName与nodeValue
05
首先获取节点对象,然后通过.nodeName和.nodeValue返回节点的名称和值.

  • 获取某个元素的节点名称和节点值:nodeName和nodeValue属性值;
  • 获取该节点的属性:ele.attributes; //返回类数组对象的该元素的所有属性
  • 获取该节点的子节点:ele.childNodes;//返回所有子节点的类数组对象
  • document.createDocumentFragment();// 创建一个文档片段
  • document.doctype; // 获取文档类型

DOM Ready

html标签需要通过浏览器渲染引擎的解析才会变成dom节点,在刷新url地址的时候就有dom构建的过程。当所有html都转化为节点后,dom树才构建完毕,简称为dom ready。
06

浏览器渲染引擎的基本渲染流程

07
渲染引擎在取得基本内容之后的基本渲染流程:
1、解析HTML,构建DOM树(构建DOM节点);
2、构建渲染树(解析样式信息,包括外部的css文件、style标签中的样式)。渲染树由一些包含有各种属性的矩形组成,他们将会按照正确的顺序显 示到屏幕上;
3、布局渲染树(布局DOM节点),执行布局的过程,将确定每个节点在屏幕上的确切坐标;
4、绘制渲染树(绘制DOM节点,即遍历渲染树),使用UI后端层来绘制每个节点

Webkit主要渲染流程:
08

参考资源:
浏览器内部工作原理: http://kb.cnblogs.com/page/129756/

DOMReady实现策略

在实际应用中,我们经常会遇到这样的场景,当页面加载完成后去做一些事情:绑定事件、DOM操作某些结点等。原来比较常用的是window的onload 事件,而该事件的实际效果是:当页面解析/DOM树建立完成,并完成了诸如图片、脚本、样式表甚至是iframe中所有资源的下载后才触发的。这对于很多 实际的应用而言有点太“迟”了,比较影响用户体验。

为了解决这个问题,ff中便增加了一个DOMContentLoaded方法,与onload相比,该方法触发的时间更早,它是在页面的DOM内容加载完成后(也就是HTML解析第一步完成)即触发,而无需等待其他资源的加载。Webkit引擎从版本525(Webkit nightly 1/2008:525+)开始也引入了该事件,Opera中也包含该方法。
即DOMReady实现策略:

  1. 支持DOMContentLoaded事件的,就使用DOMContentLoaded事件.(低版本ie下不支持DOMContentLoaded事件;)
  2. 不支持的,就用来自Diego Perini发现的著名Hack兼容。兼容原理大概就是,通过IE中的document.documentElement.doScroll('left')来判断DOM树是否创建完毕.
    DomReady的实现
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    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();
    }
    }
    }
    }

各大主流框架DOMReay是如何实现的:
http://www.cnblogs.com/JulyZhang/archive/2011/02/12/1952484.html

总结:window.onload VS DOMReady

  • window.onload: 等所有资源加载完
  • document.ready: DOM树构建完资源还没加载完
    onload事件是要在所有请求都完成之后才执行,而domReady利用hack技术,在加载完dom树之后就能执行,所以domReady比onload执行时间更早,建议采用domReady。
    使用ready保证用户体验。否则当网站有很多图片资源时要很长时间才能加载完这段时间内Js都用不了
    同时也可以去了解各大js框架,例如jquery,ext等,他们的domReady的实现机制.

如何判断元素节点类型

09
四种方法:

  • isElement 是否是元素节点
  • isHTML 是否是HTML的元素节点
  • isXML 是否是XML的元素节点
  • contains 是否是包含关系

    如何判断节点时是素节点

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    var testDiv = document.createElement('div');
    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 a = {
    nodeType: 1
    }
    console.log(isElement(document.getElementById("test")));
    console.log(isElement(document.getElementById("test").nextSibling));
    console.log(isElement(a));

如何判断节点是HTML和xml元素节点

先使用isElememt判断是否为元素节点,再用creatElement判断元素名大写小写是否都等同,大小写不等同为XML,等同为HTML
XML与html对象均支持createElement()方法,通过比较创建的元素时传入参数的【大小写】不同的情况下,元素的nodeName是否相同来判断是哪一种文档对象。如果nodeName相同则为html对象,反之为XML对象。

1
2
3
4
5
6
7
8
var isHTML = function(doc) {
return doc.createElement("p").nodeName === doc.createElement("P").nodeName;
}
console.log(isHTML(document));

var isXML = function(doc) {
return doc.createElement("p").nodeName !== doc.createElement("P").nodeName;
}

如何判断节点的包含关系:contains

元素之间的包含关系,用自带的contains方法.

1
2
3
var pNode = document.getElementById("p-node");
var cNode = document.getElementById("c-node").childNodes[0];
alert(pNode.contains(cNode));

contains方法,只有当两个都是元素节点,才能兼容各个浏览器,否则ie浏览器有的版本是不支持的,可以采用hack技术,自己写一个contains方法去兼容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function fixContains(a, b) {
try {
while ((b = b.parentNode)){
if (b === a){
return true;
}
}
return false;
} catch (e) {
return false;
}
}
var pNode = document.getElementById("p-node");
var cNode = document.getElementById("c-node").childNodes[0];
alert(fixContains(pNode, cNode));
//alert(fixContains(document, cNode));

DOM节点继承层次与嵌套规则

DOM节点继承层次

10

HTML嵌套规则

HTML存在许多种类型的标签,有的标签下面只允许特定的标签存在,这就叫HTML嵌套规则。
不按HTML嵌套规则写,浏览器就不会正确解析,会将不符合嵌套规则的节点放到目标节点的下面,或者变成纯文本。

块状元素与内联元素嵌套规则

  1. 块状元素可以包含内联元素或某些块元素,但内联元素却不能包含块元素,它只能包含其他的内联元素。
  2. 块级元素不能放在<p>里面。
  3. 有几个特殊的块级元素只能包含內联元素,不能再包含块级元素,这几个特殊的标签:h1-h6,p,dt。
  4. li内可以包含div标签。(两者都是装载内容的容器,没有级别之分,同理,li内可以容纳ul/ol)
  5. 块级元素与块级元素并列,内联元素与内联元素并列。
    <div><h2></h2><span></span></div>不提倡

某些特殊元素的嵌套规则
热点链接系列:

1
2
3
4
5
<img src="图形文件名" alt="" usemap="#图的名称">
<map name="图的名称">
<area shape="形状" coords="区域坐标列表" href="URL资源地址">
<area shape="形状" coords="区域坐标列表" href="URL资源地址">
</map>

  • shape:定义热点形状。rect(矩形) | circle(圆形) | poly(多边形)
  • 矩形:必须使用四个数字,前两个数字为左上角坐标,后两个数字为右下角坐标
    <area shape="rect" coords="100,50,200,75" href="URL">
  • 圆形:必须使用三个数字,前两个数字为圆心的坐标,最后一个数字为半径长度。
    <area shape="circl" coords="85,155,30" href="URL">
  • 任意图形(多边形):将图形之每一转折点坐标依序填入
    <area shape="poly" coords="232,70,285,70,300,90,250,90,200,78" href="URL">

参考资源:

  1. DOM探索之基础详解篇:http://www.imooc.com/learn/488
坚持原创技术分享,您的支持将鼓励我继续创作!