陈童的博客's Archivers

From everyinch on 2013-11-22 08:39:34

JavaScript的语言特性 — DOM

文档对象模型(Document Object Model,DOM)是一个表达XML文档的标准,大部分Web开发的编程语言都提供了相应的DOM实现。DOM给开发者提供了一种定位XML层级结构的直观方法。
可以把XML的DOM表达方式看作是一颗导航树。一切术语都跟家谱术语(父,子,兄弟)类似。而与家谱的不同之处在于,XML文档从一个独立的根节点(称作文档元素,document element)开始,它包含指向子节点的指针。每个子节点都包含指针指向它的父节点、相邻节点和子节点。
DOM还使用了一些特殊的术语来描述XML树里的对象种类。DOM树中的每个对象都是节点(node)。每个节点都可以有一个类型(type),比如元素、文本或者文档。要进一步学习DOM,必须了解DOM是如何表现和如何定位的。例如:

<p><strong>Hello</strong> how are you doing?</p>

这个片段的每一部分都分解为独立的DOM节点指针,指向其亲戚(父,子,兄弟),使用图谱来表示的话,它应该如下图所示:

<img class="alignnone size-full wp-image-3548" alt="dom1" src="http://www.everyinch.net/wp-content/uploads/2013/11/dom1.jpg" width="520" height="330" />

每个独立的DOM节点都包含指向它的相关节点的一系列指针。需要使用这些指针来遍历DOM,所有可用的指针如下图:

<img class="alignnone size-full wp-image-3549" alt="dom2" src="http://www.everyinch.net/wp-content/uploads/2013/11/dom2.jpg" width="456" height="289" />

通过下面的HTML文档来学习DOM的使用:

[code lang="html"]


Introduction to the DOM


Introduction to the DOM

There are a number of reasons why the DOM is awesome, here are some:





[/code]

在这个文档中,根元素是<html>元素,可以通过下面的语句获得:
document.documentElement
根节点同样具有用于定位的指针,使用这些指针就可以浏览整个文档,定位到任何一个元素。比如,要获取<h1>:
document.documentElement.firstChild.nextSibling.firstChild // 试图获取< h1 > 不起作用

DOM指针不仅可以指向元素,也可以指向文本节点,这行代码并会真正指向<h1>元素,而是指向了<title>元素。这是由于空格的原因,在<html>和<head>元素之间有一个行结束符,它被认为是空格,这就意味着第一个节点是文本节点,而不是<head>元素。总结三点:

当试图只使用指针来遍历DOM时,精细编写的HTML标记会产生混乱
仅使用DOM指针来定位文档可能会过于繁琐和不切实际
通常不需要直接存取文本节点,只存取包含文本节点的元素即可

下面的代码用来删除文档中的所有空格,让DOM遍历更容易。但是需要注意的是,这个函数的结果不是持久的,它需要在HTML文档的每一次加载时都重新执行一遍。

[code lang="js"]
function cleanWhitespace( element ) {
// 如果不提供参数,则处理整个HTML文档
element = element || document;
// 使用第一个子节点作为开始指针
var cur = element.firstChild;

// 一直到没有子节点为止
while ( cur != null ) {

// 如果节点是文本节点,且只包含空格
if ( cur.nodeType == 3 && ! /\S/.test(cur.nodeValue) ) {
// 删除这个文本节点
element.removeChild( cur );

// 否则,它就是一个元素节点
} else if ( cur.nodeType == 1 ) {
// 递归整个文档
cleanWhitespace( cur );
}

cur = cur.nextSibling; // 遍历子节点
}
}
[/code]

如果使用了上面的代码之后再查找<h1>元素后的元素,那么代码应该这样:

[code lang="js"]
cleanWhitespace();
// 查找 < h1 > 元素
document.documentElement
.firstChild // 查找 head 元素
.nextSibling // 查找
.firstChild // 得到 h1 元素
.nextSibling // 得到相邻的段落
[/code]

删除文档中所有空格的代码可以保证遍历DOM文档的稳定性,但明显性能太差了。这个函数使用了节点类型,节点类型可以通过 nodeType 属性来确定,可能会出现的值包括:

元素(nodeType=1):匹配XML文档中的元素,例如<li>、<p>等
文本(nodeType=3):匹配文档中的文本块
文档(nodeType=9):匹配文档的根元素,在HTML文档中是<html>元素

大部分Web开发者不多数情况下仅仅需要遍历DOM元素,可以编写一些辅助函数来达到这个目的,可以取代标准的previousSibling、nextSibling、firstChild、lastChild和parentNode。

查找相关元素的前一个兄弟元素的函数
[code lang="js"]
function prev( elem ) {
do {
elem = elem.previousSibling;
} while ( elem && elem.nodeType != 1 );
return elem;
}
[/code]

查找相关元素的下一个兄弟元素的函数
[code lang="js"]
function next( elem ) {
do {
elem = elem.nextSibling;
} while ( elem && elem.nodeType != 1 );
return elem;
}
[/code]

查找元素第一个子元素的函数
[code lang="js"]
function first( elem ) {
elem = elem.firstChild;
return elem && elem.nodeType != 1 ?
nextSibling( elem ) : elem;
}
[/code]

查找元素最后一个子元素的函数
[code lang="js"]
function last( elem ) {
elem = elem.lastChild;
return elem && elem.nodeType != 1 ?
prevSibling( elem ) : elem;
}
[/code]

查找元素父元素的函数
[code lang="js"]
function parent( elem, num ) {
num = num || 1;
for ( var i = 0; i < num; i++ )
if ( elem != null ) elem = elem.parentNode;
return elem;
}
[/code]

如果要查找<h1>元素的下一个元素,可以这样:
// 查找 < h1 > 元素的下一个元素
next( first( document.body ) )

查看完整版本: JavaScript的语言特性 — DOM

Tags:


©陈童的博客