DOM1级主要定义的是HTML和XML文档的底层结构。DOM2和DOM3级则在这个结构的基础上引入了更多的交互能力,也支持了更高级的XML特性。为此DOM2和DOM3级分为许多模块,这些模块如下:

DOM2级核心;

DOM2级视图;

DOM2级事件;

DOM2级样式;

DOM2级遍历和范围;

DOM2级HTML。

一、DOM变化

DOM2级和3级的目的在于扩展DOM API,以满足操作XML的所有需求,同时提供更好的错误处理及特性检测能力。

1.针对XML命名空间的变化

有了XML命名空间,不同的XML文档的元素就可以混在一起,共同构成良好的文档,而不必担心发生命名冲突。

命名空间要使用xmlns特性来指定。XHTML的命名空间是http://www.w3.org/1999/xhtml,在任何格式良好XHTML页面中,都应该将其包含在<html>元素中,如下面的例子所示:

<html  xmlns = “http://www.w3.org/1999/xhtml”>

<head>

<title>Example XHTML page</title>

</head>

<body>

Hello world!

</body>

</head>

对这个例子而言,其中的所有元素都默认被视为XHTML命名空间中的元素。想要明确地为XML命名空间创建前缀,可以使用xmlns后跟冒号,再后跟前缀,如下所示:

<xhtml:html xmlns:xhtml =”http://www.w3.org/1999/xhtml”>

<xhtml:head>

<xhtml:title>Example XHTML page</xhtml:title>

</xhtml:head>

<xhtml:body>

Hello world!

</xhtml:body>

</xhtml:html>

①Node类型的变化

在DOM2级中,Node类型包含下列特定于命名空间的属性。

localName:不带命名空间前缀的节点名称

namespaceURI:命名空间URI或者(在未指定的情况下是)null。

prefix:命名空间前缀或者(在未指定的情况下是)null。

DOM3级在此基础上更进一步,又引入了下列与命名空间有关的方法:

isDefaultNamespace(namespaceURI):在指定的namespaceURI是当前节点的默认命名空间的情况下返回true。

lookupNamespaceURI(prefix):返回给定prefix的命名空间。

lookupPrefix(namespaceURI):返回给定namespaceURI的前缀。

②Document类型的变化

DOM2级中的Document类型也发生了变化,包含了下列与命名空间有关的方法:

createElementNS(namespaceURI,tagName):使用给定的tagName创建一个属于命名空间namespaceURI的新元素。

createAttributeNS(namespaceURI,attributeName):使用给定的attributeName创建一个属于命名空间namespaceURI的新特性。

getElementsByTagNameNS(namespaceURI,tagName):返回属于命名空间namespaceURI的tagName元素的NodeList。

③Element类型的变化

DOM2级核心中有关Element的变化,主要涉及操作特性。新增的方法如下:

getAttributeNS(namespaceURI,localName):取得属于命名空间namespaceURI且名为localName的特性。

getAttributeNodesNS(namespaceURI,localName):取得属于命名空间namespaceURI且名为localName的特性节点。

getElementsByTagNameNS(namespaceURI,localName):返回属于命名空间namespaceURI的tagName元素的NodeList。

has AttributeNS(namespaceURI,localName):确定当前元素是否有一个名为localName的特性,而且该命名空间是namespaceURI。

removeAttributeNS(namespaceURI,localName):删除属于命名空间namespaceURI且名为localName的特性。

setAttributeNS(namespaceURI,qualifiedName,value):设置属于命名空间namespaceURI且名为qualifiedName的特性的值为value。

setAttributeNodeNS(attNode):设置属于命名空间namespaceURI的特性节点。

④NamedNodeMap类型的变化

namedNodeMap类型也新增了下列与命名空间有关的方法。由于特性是通过NamedNodeMap表示的,因此这些方法多数情况下只针对特性使用。

getNamedItemNS(namespaceURI,localname):取得命名空间namespaceURI且名为localName的项。

removeNamedItemNS(namespaceURI,localName):移除属于命名空间namespaceURI且名为localName的项。

setNamedItemNS(node):添加node,这个节点已经事先指定了命名空间信息。

2.其他方面的变化

①DocumentType类型的变化

DocumentType类型新增了3个属性:publicId、systemId和internalSubset。其中,前两个属性表示的是文档类型声明中的两个信息段,这两个信息段在DOM1级中是没有办法访问到的。

②Document类型的变化

Document类型的变化中唯一与命名空间无关的方法是importNode()。这个方法的用途是从一个文档中取得一个节点,然后将其导入到另一个文档,使其成为这个文档结构的一部分。

importNode()方法与Element的cloneNode方法非常相似,它接受两个参数:要复制的节点和一个表示是否复制子节点的布尔值。返回的结果是原来节点的副本,但能够在当前文档中使用。

③Node类型的变化

Node类型中唯一与命名空间无关的变化,就是添加了isSupported()方法。与DOM1级为document.implementation引入的hasFeature()方法类似,isSupported()方法用于确定当前节点具有什么能力。这个方法也接受相同的两个参数:特性名和特性版本号。如果浏览器实现了相应特性,而且能够基于给定节点执行该特性,isSupported()就返回true。

DOM3级引入了两个辅助比较节点的方法:isSameNode()和isEqualNode()。这两个方法都接受一个节点参数,并在传入节点与引用的节点相同或相等时返回true。所谓相同,指的是两个节点引用的是同一个对象。所谓相等,指的是两个节点是相同的类型,具有相等的属性,而且它们的attributes和childNodes属性也相等。

DOM3级还针对DOM节点添加额外数据引入了新方法。其中,setUserData()方法会将数据指定给节点,它接受3个参数:要设置的键、实际的数据和处理的函数。以下代码可以将数据指定给一个节点。

document.body.setUserData(”name”,”Nicholas”,function(){ });

然后,使用getUserData()并传入相同的键,就可以获得该数据,如下所示:

var value=document.body.getUserData(”name”);

传入setUserData()中的处理函数会在带有数据的节点被复制、删除、重命名或引入一个文档时调用,因而你可以事先决定在上述操作发生时如何处理用户数据。处理函数接受5个参数:表示操作类型的数值(1表示复制、2表示导入、3表示删除、4表示重命名)、数据键、数据值、源节点和目标节点。在删除节点时,源节点是null;除在复制节点时,目标节点均为null。在函数内部,你可以决定如何存储数据。

④框架的变化

框架和内嵌框架分别用HTMLFrameElement和HTMLFrameElement表示,它们在DOM2级中都有了一个新属性,名叫contentDocument。这个属性包含一个指针。指向表示框架内容的文档对象。

二、样式

1.访问元素的样式

任何支持style特性的HTML元素在javascript中都有一个对应的style属性。这个style对象是CSSStyleDeclaration的实例,包含着通过HTML的style特性指定的所有样式信息,但不包含与外部样式表嵌入样式表经层叠而来的样式。在style特性中指定的任何CSS属性都将表现为这个style对象的相应属性。对于使用短划线的CSS属性名,必须将其转换成驼峰大小写形式,才能通过javascript来访问。例如:CSS中的background-image属性对应的javascript属性为style.backgroundImage。

多数情况下,都可以通过简单地转换属性名的格式来实现转换。其中一个不能直接转换的CSS属性就是float。由于float是javascript中的保留字因此不能用作属性名。

①DOM样式属性和方法

“DOM2级样式”规范还为style对象定义了一些属性和方法。这些属性和方法提供元素的style特性值的同时,也可以修改样式。下面列出了这些属性和方法:

cssText:如前所述,通过它能够访问到style特性中的CSS代码。

length:应用给元素的CSS属性的数量。

parentRule:表示CSS信息的CSSRule对象。

getPropertyCSSValue(propertyName):返回包含给定属性值的CSSValue对象。

getPropertyPriority(propertyName):如果给定的属性使用了!important设置,则返回“!important”;否则,返回空字符串。

getPropertyValue(propertyName):返回给定属性的字符串。

item(index):返回给定位置的CSS属性的名称。

removeProperty(propertyName):从样式中删除给定属性。

setProperty(propertyName,value,priority):将给定属性设置为相应的值,并加上优先权标志(“important”或者一个空字符串)。

②计算的样式

“DOM2级样式”增强了document.defaultView,提供了getComputedStyle()方法。这个方法接收两个参数:要取得计算机样式的元素和一个伪元素字符串,如“:after”,如果不需要伪元素信息,第二个参数可以是null。返回一个CSSStyleDeclaration对象,其中包含当前元素的所有计算的样式。例如:

<!DOCTYPE html>

<html>

<head>

<title>Computed Style Example</title>

<style type="text/css">

#myDiv{

background-color: blue;

width: 100px;

height: 200px;

}

</style>

</head>

<body>

<div id="myDiv" style="background-color:red;border:1px solid black"></div>

</body>

</html>

以下代码取得这个元素计算后的样式:

var myDiv=document.getElementById(“myDiv”) ;

var computedStyle = document.defaultView.getComputedStyle(myDiv , null) ;

alert(computedStyle.backgroundColor) ;     // ”red”

alert(computedStyle.width) ;              // “100px”

alert(computedStyle.height) ;              //”200px”

alert(computedStyle.border) ;              //在某些浏览器中是”1px solid black”

需要注意的是:所有计算的样式都是只读的;不能修改计算后样式对象中的CSS属性。此外,计算后的样式也包含属于浏览器内部样式表的样式信息,因此任何具有默认值的CSS属性都会表现在计算后的样式中。

2.操作样式表

CSSStyleSheet类型表示的是样式表,以下代码可以确定浏览器是否支持DOM2级样式表:

var supportsDOM2StyleSheets =

document.implementation.hasFeature(“StyleSheets”, “2.0”) ;

CSSStyleSheet继承自StyleSheet,后者可以作为一个基础接口来定义非CSS样式表。

①CSS规则

CSSRule对象表示样式表中的每一条规则。CSSRule是一个供其他多种类型继承的基类型,其中最常见的就是CSSStyleRule类型,表示样式信息。

②创建规则

DOM规定,要向现有样式表中添加新规则,需要使用insetRule()方法。这个方法接受两个参数:规则文本和表示在哪里插入规则的索引。下面是一个例子:

sheet.insertRule(“body { background-color : silver }” , 0 ) ;   //DOM方法。

这个例子插入的规则会改变元素的背景颜色。插入的规则将成为样式表中的第一条规则。

IE及更早版本支持一个类似的方法,名叫addRule(),也接受两必选参数:选择符文本和CSS样式信息;一个可选参数:插入规则的位置。例如:

sheet.addRule(“body” , “background-color : silver” , 0 ) ;      // 仅对IE有效

要以跨浏览器的方式向样式表中插入规则,可以使用下面的函数。这个函数接受4个参数:要向其中添加规则的样式表以及与addRule()相同的3个参数。下面是调用这个函数的代码:

insertRule(document.styleSheets[0] , “body”, “background-color : silver” , 0) ;

③删除规则

从样式表中删除规则的方法是deleteRule(),这个方法接受一个参数:要删除的规则的位置。例如,要删除样式表中的第一条规则,可以使用以下代码:

sheet.deleteRule(0);       //DOM方法

IE支持类似的方法叫做removeRule(),使用方法相同,如下所示:

sheet.removeRule(0);    //仅对IE有效

下面是一个能够跨浏览器删除规则的函数,第一个参数是要操作的样式表,第二个参数是要删除的规则的索引。

调用这个方法如下:

deleteRule(document.styleSheets[0] , 0) ;

3.元素大小

①偏移量

元素的可见大小由其高度、宽度决定,包括所有内边距、滚动条和边框大小。通过下列4个属性可以取得元素的偏移量:

offsetHeight:元素在垂直方向上占用的空间大小,以像素计。包括元素的高度、水平滚动条的高度、上边框高度和下边框高度。

offsetWidth:元素在水平方向上占用的空间大小,以像素计。包括元素的宽度、垂直滚动条的宽度、左边宽度和右边框宽度。

offsetLeft:元素的左外边框至包含元素的左内边框之间的像素距离。

offsetTop:元素的上外边框至包含元素的上内边框之间的像素距离。

其中,offsetLeft和offsetTop属性与包含元素有关,包含元素的引用保存在offsetParent属性中。offsetParent属性不一定与parentNode的值相等。

②客户区大小

元素的客户区大小,指的是元素内容及其内边距所占据的空间大小。有关客户区大小的属性有两个:clientWidth和clientHeight。其中,clientWidth属性时元素内容区宽度加上左右内边距宽度;clientHeight属性时元素内容区高度加上上下内边距高度。

③滚动大小

指的是包含滚动内容的元素的大小。以下是4个与滚动大小相关的属性

scrollHeight:在没有滚动条的情况下,元素内容的总高度。

scrollWidth:在没有滚动条的情况下,元素内容的总宽度。

scrollLeft:被隐藏在内容区域左侧的像素数。通过设置这个属性可以改变元素的滚动位置。

scrollTop:被隐藏在内容区域上方的像素数。通过设置这个属性可以改变元素的滚动位置。

scrollWidth和scrollHeight主要用于确定元素内容的实际大小。

④确定元素大小

getBoundingClientRect()方法。这个方法会返回一个矩形对象,包含4个属性:left、top、right、bottom。这些属性给出了元素在页面中相对于视口的位置。

三、遍历

“DOM2级遍历和范围”模块定义了两个用于辅助完成顺序遍历DOM结构的类型:NodeIterator和TreeWalker。这两个类型能够基于给定的起点对DOM结构执行深度优先的遍历操作。遍历以给定节点为根,不可能向上超出DOM树的根节点。

1.NodeIterator

Nodelterator类型是两者中比较简单的一个,可以使用document.createNodeIterator()方法创建它的新实例。这个方法接受4个参数:

root:想要作为搜索起点的树中的节点。

whatToShow:表示要访问哪些节点的数字代码

filter:是一个NodeFilter对象,或者一个表示应该接受还是拒绝某种特定节点的函数。

entityReferenceExpansion:布尔值,表示是否要扩展实体引用。

whatToShow参数是一个位掩码,通过应用一或多个过滤器来确定要访问哪些节点。

Nodelterator类型的两个方法是nextNode()和previousNode()。顾名思义,在深度优先的DOM子树遍历中,nextNode()方法用于向前前进一步,而previousNode()用于向后后退一步。

2.TreeWalker

TreeWalker是NodeIterator的一个更高级的版本。除了包括nextNode()和previousNode()在内的相同的功能之外,这个类型还提供了下列用于在不同方向上遍历DOM结构的方法:

parentNode():遍历到当前节点的父节点;

firstChild():遍历到当前节点的第一个子节点;

lastChild():遍历到当前节点的最后一个子节点;

nextSibling():遍历到当前节点的下一个同辈节点;

previousSibling():遍历到当前节点的上一个同辈节点。

创建TreeWalker对象要使用document.createTreeWalker( )方法,这个方法接受4个参数与document.createNodeIterator( )方法相同:作为遍历起点的根节点、要显示的节点类型、过滤器和一个表示是否扩展实体引用的布尔值。由于这两个创建方法很相似,所以很容易用TreeWalker来代替NodeIterator。

4.范围

(1)DOM中的范围

DOM2级在Document类型中定义了createRange( )方法。在兼容DOM的浏览器中,这个方法属于document对象。使用hasFeature()或者直接检测该方法,都可以确定浏览器是否支持范围。如果浏览器支持范围,那么就可以使用createRange()来创建DOM范围。

①用DOM范围实现简单选择

要使用范围来选择文档中的一部分,最简单的方式就是使用selectNode()或selectNodeContents()。这两个方法都接受一个参数:一个DOM节点。其中,selectNode()方法选择整个节点,包括其子节点;而selectNodeContents()方法则只选择节点的子节点。

②用DOM范围实现复杂选项

要创建复杂范围就得使用setStart()和setEnd()方法。这两个方法都接受两个参数:一个参照节点和一个偏移量值。对setStart()来说,参照节点会变成:startContainer,而偏移量值会变成startOffset。对于setEnd()来说,参照节点会变成endContainer,而偏移量值会变成endOffset。

③操作DOM范围中的内容

在创建范围时,内部会为这个范围创建一个文档片段,范围所属的全部节点都被添加到了这个文档片段中。为了创建这个文档片段,范围内容的格式必须正确有效。

第一个方法:deleteContents()。这个方法能够从文档中删除范围所包含的内容。例如:

var p1 = document.getElementById(“p1”) ;

helloNode = p1.firstChild.firstChild ;

worldNode = p1.lastChild ;

range = document.createRange() ;

range = setStart(helloNode , 2 ) ;

range = setEnd(worldNode , 3 ) ;

range.deleteContents( ) ;

执行以上代码后,页面中会显示如下HTML代码:

<p><b>He</b>rld!</p>

与deleteContents()方法相似,extractContents()也会从文档中移除范围选区。但这两个方法的区别在于,extractContents()会返回范围的文档片段。利用这个返回值,可以将范围的内容插入到文档中的其他地方。

还有一种做法,即使用cloneContents()创建范围对象的一个副本,然后在文档的其他地方插入该副本。

④插入DOM范围中的内容

使用insertNode()方法可以向范围选区的开始处插入一个节点。

使用surroundContents()方法可以环绕范围插入内容,这个方法接收一个参数,即环绕范围内容的节点,在环绕范围插入内容时,后台会执行下列步骤:

提取出范围中的内容;

将给定节点插入到文档中原来范围所在的位置上;

将文档片段的内容添加到给定节点中。

⑤折叠DOM范围

所谓折叠范围, 就是指范围中未选择文档的任何部分。

使用collapse()方法来折叠范围,这个方法接收一个参数,一个布尔值,表示要折叠到范围的哪一端。参数true表示折叠刀范围的起点,参数false表示折叠刀范围的终点。要确定范围已经折叠完毕,可以检查collapsed属性,如下所示:

range.collapse(true) ;          //折叠到起点

alert(range.collapsed) ;         //输出true

⑥比较DOM范围

在多个范围的情况下,可以使用compareBoundaryPoints()方法来确定这些范围是否有公共的边界。这个方法接受两个参数:表示比较方式的常量值和要比较的范围。

⑦复制DOM范围

可以使用cloneRange()方法复制范围。这个方法会创建调用它的范围的一个副本。

var newRange = range.cloneRange();

新创建的范围与原来的范围包含相同的属性,而修改它的端点不会影响原来的范围。

⑧清理DOM范围

使用完范围之后,最好是调用detach()方法,以便从创建范围的文档中分离出该范围。调用detach()之后,就可以放心地解除对范围的引用,从而让垃圾回收机制回收其内存了。

(2)IE8及更早版本的范围

①用IE范围实现简单的选择

选择页面中某一区域的最简单方式,就是使用范围的findText()方法。这个方法会找到第一次出现的给定文本,并将范围移过来以环绕该文本。

②使用IE范围实现复杂的选择

在IE中创建复杂范围的方法,就是以特定的增量向四周移动范围。为此,IE提供了4个方法:move()、moveStart()、moveEnd()、expand()。这些方法都接受两个参数:移动单位和移动单位的数量。

③操作IE范围中的内容

在IE中操作范围中的内容可以使用text属性或pasteHTML()方法。如前所述,通过text属性可以取得范围中的内容文本;但是,也可以通过这个属性设置范围中的内容文本。

④折叠IE范围

IE为范围提供的collapse()方法与相应的DOM方法用法一样。

⑤比较IE范围

IE中的compareEndPoints()方法与DOM范围的compareBoundaryPoints()方法类似。这个方法接受两个参数:比较的类型和要比较的范围。

⑥复制IE范围

在IE中使用duplicate()方法可以复制文本范围,结果会创建原范围的一个副本,如下面的例子所示:

var newRange = range.duplicate() ;

新创建的范围会带有与原范围完全相同的属性。

05-04 11:22