第 12 章 DOM2 和 DOM3

132 阅读8分钟

DOM1级主要定义的是 HTML 和 XML 文档的底层结构。DOM2 和 DOM3级则在这个结构的基础上引入了更多的交互能力,也支持了更高级的XML特性。为此,DOM2 和 DOM3级分为许多模块(模块之间具有某种关联),分别描述了 DOM 的某个非常具体的子集。

  • DOM2 级核心(DOM Level 2 Core):在 1 级核心基础上构建,为节点添加了更多方法和属性。
  • DOM2 级视图(DOM Level 2 Views):为文档定义了基于样式信息的不同视图。
  • DOM2 级事件(DOM Level 2 Events):说明了如何使用事件与 DOM 文档交互。
  • DOM2 级样式(DOM Level 2 Style):定义了如何以编程方式来访问和改变 CSS 样式信息。
  • DOM2 级遍历和范围(DOM Level 2 Traversal and Range):引入了遍历 DOM 文档和选择其特定部分的新接口。
  • DOM2 级 HTML(DOM Level 2 HTML):在 1 级 HTML 基础上构建,添加了更多属性、方法和新接口。

12.1 DOM 变化

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

12.1.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>
</html>

在混合使用两种语言的情况下,命名空间的用处就非常大了

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Example XHTML page</title>
    </head>
    <body>
        <svg xmlns="http://www.w3.org/2000/svg" version="1.1"viewBox="0 0 100 100" style="width:100%; height:100%">
            <rect x="0" y="0" width="100" height="100" style="fill:red"/>
        </svg>
    </body>
</html>

在这个例子中,通过设置命名空间,将<svg>标识为了与包含文档无关的元素。

12.2 样式

在 HTML 中定义样式的方式有 3 种:通过元素包含外部样式表文件、使用元素定义嵌入式样式,以及使用 style 特性定义针对特定元素的样式。。“DOM2 级样式”模块围绕这 3 种应用样式的机制提供了一套 API。

12.2.1 访问元素的样式

任何支持 style 特性的 HTML 元素在 JavaScript 中都有一个对应的 style 属性。这个 style 对象是 CSSStyleDeclaration 的实例,包含着通过 HTML 的 style 属性中指定的所有样式信息,但不包含与外部样式表或嵌入样式表经层叠而来的样式。

var myDiv = document.getElementById("myDiv");

//设置背景颜色
myDiv.style.backgroundColor = "red";

//改变大小
myDiv.style.width = "100px";
myDiv.style.height = "200px";

//指定边框
myDiv.style.border = "1px solid black";

getComputedStyle()方法接受两个参数:要取得计算样式的元素和一个伪元素字符串(例如":after")。如果不需要伪元素信息,第二个参数可以是 null。方法返回一个 CSSStyleDeclaration 对象,其中包含当前元素的所有计算的样式。

IE 不支持 getComputedStyle()方法,但它有一种类似的概念是currentStyle属性。

12.2.2 操作样式表

CSSStyleSheet 类型表示的是样式表,包括通过<link>元素包含的样式表和在<style>元素中定义的样式表。有读者可能记得,这两个元素本身分别是由 HTMLLinkElement 和 HTMLStyleElement 类型表示的。但是,CSSStyleSheet 类型相对更加通用一些,它只表示样式表,而不管这些样式表在 HTML中是如何定义的。

12.2.3 元素大小

DOM中没有规定如何确定页面中元素的大小。IE 为此率先引入了一些属性,以便开发人员使用。目前,所有主要的浏览器都已经支持这些属性。

偏移量

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

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

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

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

  • offsetTop:元素的上外边框至包含元素的上内边框之间的像素距离。 其中,offsetLeft 和 offsetTop 属性与包含元素有关,包含元素的引用保存在 offsetParent属性中。

offsetParent属性:是一个只读属性,返回一个指向最近的(指包含层级上的最近)包含该元素的定位元素或者最近的 tabletdthbody 元素。

image.png

客户区大小

元素的客户区大小(client dimension),指的是元素内容及其内边距所占据的空间大小。。有关客户区大小的属性有两个:clientWidth 和 clientHeight。

clientWidth:是元素内容区宽度加上左右内边距宽度; clientHeight:是元素内容区高度加上上下内边距高度;

image.png

滚动大小

滚动大小(scroll dimension),指的是包含滚动内容的元素的大小。有些元素(例如 <html>元素),即使没有执行任何代码也能自动地添加滚动条;但另外一些元素,则需要通过 CSS 的overflow 属性进行设置才能滚动。

  • scrollHeight:在没有滚动条的情况下,元素内容的总高度。
  • scrollWidth:在没有滚动条的情况下,元素内容的总宽度。
  • scrollLeft:被隐藏在内容区域左侧的像素数。通过设置这个属性可以改变元素的滚动位置。
  • scrollTop:被隐藏在内容区域上方的像素数。通过设置这个属性可以改变元素的滚动位置。

image.png

在确定文档的总高度时(包括基于视口的最小高度时),必须取得 scrollWidth/clientWidth 和 scrollHeight/clientHeight 中的最大值,才能保证在跨浏览器的环境下得到精确的结果。下面就 是这样一个例子。

var docHeight = Math.max(document.documentElement.scrollHeight,document.documentElement.clientHeight);

var docWidth = Math.max(document.documentElement.scrollWidth,document.documentElement.clientWidth);

通过 scrollLeft 和 scrollTop 属性既可以确定元素当前滚动的状态,也可以设置元素的滚动位置。

    如果元素被垂直滚动了,那么 scrollTop 的值会大于 0,且表示元素上方不可见内容的像素高度。
    如果元素被水平滚动了,那么 scrollLeft 的值会大于 0,且表示元素左侧不可见内容的像素宽度。
    这两个属性都是可以设置的,因此将元素的scrollLeft 和 scrollTop 设置为 0,就可以重置元素的滚动位置。

确定元素大小

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

IE8 及更早版本认为文档的左上角坐标是(2, 2),标准浏览器左上角为(0, 0)

12.3 遍历

“DOM2 级遍历和范围”模块定义了两个用于辅助完成顺序遍历 DOM 结构的类型:NodeIterator 和 TreeWalker。这两个类型能够基于给定的起点对 DOM 结构执行深度优先(depth-first)的遍历操作。

12.3.1 NodeIterator

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

  • root:想要作为搜索起点的树中的节点。
  • whatToShow:表示要访问哪些节点的数字代码。
  • filter:是一个 NodeFilter 对象,或者一个表示应该接受还是拒绝某种特定节点的函数。
  • entityReferenceExpansion:布尔值,表示是否要扩展实体引用。这个参数在 HTML 页面 中没有用,因为其中的实体引用不能扩展。

12.3.2 TreeWalker

TreeWalker 是 NodeIterator 的一个更高级的版本。

  • parentNode():遍历到当前节点的父节点;
  • firstChild():遍历到当前节点的第一个子节点;
  • lastChild():遍历到当前节点的最后一个子节点;
  • nextSibling():遍历到当前节点的下一个同辈节点;
  • previousSibling():遍历到当前节点的上一个同辈节点。

使用 document.createTreeWalker()方法,这个方法接受的 4 个参数与 document.createNodeIterator()方法相同。

12.4 范围

“DOM2 级遍历和范围”模块定义了“范围”(range)接口。通过范围可以选择文档中的一个区域,而不必考虑节点的界限(选择在后台完成,对用户是不可见的)。

12.4.1 DOM中的范围

DOM2 级在 Document 类型中定义了 createRange()方法。每个范围由一个 Range 类型的实例表示,这个实例拥有很多属性和方法。

  • startContainer:包含范围起点的节点(即选区中第一个节点的父节点)。
  • startOffset:范围在 startContainer 中起点的偏移量。
  • endContainer:包含范围终点的节点(即选区中最后一个节点的父节点)。
  • endOffset:范围在 endContainer 中终点的偏移量(与 startOffset 遵循相同的取值规则)。
  • commonAncestorContainer:startContainer 和 endContainer 共同的祖先节点在文档树中位置最深的那个。

要使用范围来选择文档中的一部分,最简的方式就是使用selectNode()方法:选择整个节点,包括其子节点;或者selectNodeContents()方法:则只选择节点的子节点。

<html>
    <body>
        <p id="p1"><b>Hello</b> world!</p>
    </body>
</html>
var range1 = document.createRange();
range2 = document.createRange();
p1 = document.getElementById("p1");
range1.selectNode(p1);
range2.selectNodeContents(p1); // p1的子节点。

image.png

12.4.2 IE8 及更早版本中的范围

IE8 及早期版本支持一种类似的概念,即文本范围(text range)。通过<body>、<button>、<input>和<textarea>等这几个元素,可以调用 createTextRange()方法来创建文本范围。

var range = document.body.createTextRange();