JavaScript高级程序设计(第3版)学习笔记 第12章

第12章 DOM2和DOM3 

1.DOM1 级主要定义的是 HTML 和 XML 文档的底层结构。DOM2 和 DOM3 级则在这个结构的基础上引入了更多的交互能力。

  • 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 基础上构建,添加了更多属性、方法和新接口。

2.DocumentType 类型新增了 3 个属性:publicId、systemId 和 internalSubset。其中,前两个属性表示的是文档类型声明中的两个信息段,第三个用于访问包含在文档类型声明中的额外定义,很少需要在网页中访问此类信息

3.Document 类型的变化:

  • importNode()方法:从一个文档中取得一个节点,然后将其导入到另一个文档,使其成为这个文档结构的一部分,接受两个参数:要复制的节点和一个表示是否复制子节点的布尔值。
  • defaultView 的属性,其中保存着一个指针,指向拥有给 定文档的窗口(或框架)。
  • createDocumentType()方法:用于创建一个新的 DocumentType 节点,接受 3 个参数:文档类型名称、publicId、systemId。 
  • createDocument()方法:创建新文档,接受 3 个参数:针对文档中元素的 namesp- aceURI、文档元素的标签名、新文档的文档类型。
  • createHTMLDocument()方法:创建一个完整的 HTML 文档,接受一个参数,即新创建文档的标题

4.Node 类型的变化:添加了 isSupported()方法,用于确定当前节点具有什么能力,接受相同的两个参数:特性名和特性版本号。

5.框架的变化:contentDocument属性包含一个指针,指向表示框架内容的文档对象。

6.在 HTML 中定义样式的方式有 3 种:通过<link/>元素包含外部样式表文件、使用<style/>元素 定义嵌入式样式,以及使用 style 特性定义针对特定元素的样式。任何支持 style 特性的 HTML 元素在 JavaScript 中都有一个对应的 style 属性。这个 style 对象 是 CSSStyleDeclaration 的实例,包含着通过 HTML 的 style 特性指定的所有样式信息,但不包含与外部样式表或嵌入样式表经层叠而来的样式。“DOM2 级样式”规范还为 style 对象定义了一些属性和方法:

  • cssText:如前所述,通过它能够访问到 style 特性中的 CSS 代码。
  • length:应用给元素的 CSS 属性的数量。
  • parentRule:表示 CSS 信息的 CSSRule 对象。本节后面将讨论 CSSRule 类型。
  • getPropertyCSSValue(propertyName):返回包含给定属性值的 CSSValue 对象。
  • getPropertyPriority(propertyName):如果给定的属性使用了!important 设置,则返回"important";否则,返回空字符串。
  • getPropertyValue(propertyName):返回给定属性的字符串值。
  • item(index):返回给定位置的 CSS 属性的名称。
  • removeProperty(propertyName):从样式中删除给定属性。
  • setProperty(propertyName,value,priority):将给定属性设置为相应的值,并加上优先权标志("important"或者一个空字符串)。

7.要确定某个元素的计算样式(包括应用给它的所有 CSS 规则),可以使用 getComputedStyle()方法,接受两个参数:要取得计算样式的元素和一个伪元素字符串(例 如":after")。如果不需要伪元素信息,第二个参数可以是 null。getComputedStyle()方法返回一个 CSSStyleDeclaration 对象(与 style 属性的类型相同),其中包含当前元素的所有计算的样式。

<!DOCTYPE html>
<html>
<head>
    <title>Computed Styles 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"

8.可以通过 document.styleSheets 集合访问样式表。

9.通过 下列 4 个属性可以取得元素的偏移量:

  • offsetHeight:元素在垂直方向上占用的空间大小,以像素计。包括元素的高度、(可见的) 水平滚动条的高度、上边框高度和下边框高度。
  • offsetWidth:元素在水平方向上占用的空间大小,以像素计。包括元素的宽度、(可见的)垂 直滚动条的宽度、左边框宽度和右边框宽度。
  • offsetLeft:元素的左外边框至包含元素的左内边框之间的像素距离。
  •  offsetTop:元素的上外边框至包含元素的上内边框之间的像素距离。
  • //取得元素的左偏移量
    function getElementLeft(element){
        var actualLeft = element.offsetLeft;
        var current = element.offsetParent;
        while (current !== null){
            actualLeft += current.offsetLeft;
            current = current.offsetParent;
        }
        return actualLeft;
    }
    //取得元素的上偏移量
    function getElementTop(element){
        var actualTop = element.offsetTop;
        var current = element.offsetParent;
        while (current !== null){
            actualTop += current. offsetTop;
            current = current.offsetParent;
    }
        return actualTop;
    }

10.元素的客户区大小(client dimension):元素内容及其内边距所占据的空间大小,clientWidth 属性是元素内容区宽度加上左右内边距宽度;clientHeight 属性是元素内容区高度加上上下内边距高度。

//确定浏览器 视口大小
function getViewport(){
    if (document.compatMode == "BackCompat"){
        return {
            width: document.body.clientWidth,
            height: document.body.clientHeight
        };
    } else {
        return {
            width: document.documentElement.clientWidth,
            height: document.documentElement.clientHeight
        }; 
    }
}

11.滚动大小:包含滚动内容的元素的大小,4 个与滚动大小相关的属性。

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

12.跨浏览器取得元素位置

function getBoundingClientRect(element){
    var scrollTop = document.documentElement.scrollTop;
    var scrollLeft = document.documentElement.scrollLeft;

    if (element.getBoundingClientRect){
        if (typeof arguments.callee.offset != "number"){
            var temp = document.createElement("div");
            temp.style.cssText = "position:absolute;left:0;top:0;";   
            document.body.appendChild(temp);
            arguments.callee.offset = -temp.getBoundingClientRect().top -                    scrollTop; 
            document.body.removeChild(temp);
            temp = null;
        }
        var rect = element.getBoundingClientRect();
        var offset = arguments.callee.offset;
        return {
            left: rect.left + offset,
            right: rect.right + offset,
            top: rect.top + offset,
            bottom: rect.bottom + offset
        };
    } else {
        var actualLeft = getElementLeft(element);
        var actualTop = getElementTop(element);
        return {
            left: actualLeft - scrollLeft,
            right: actualLeft + element.offsetWidth - scrollLeft,
            top: actualTop - scrollTop,
            bottom: actualTop + element.offsetHeight - scrollTop
         }
    } 
}

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

(1)NodeIterator:使用 document.createNodeIterator()方 法创建它的新实例。这个方法接受下列 4 个参数:

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

两个主要方法:

  • nextNode()方法:用于向前前进一步和。
  • previousNode()方法:用于向后后退一步。
<div id="div1">
    <p><b>Hello</b> world!</p>
    <ul>
        <li>List item 1</li>
        <li>List item 2</li>
        <li>List item 3</li>
    </ul> 
</div>
//遍历<div>元素中的所有元素
var div = document.getElementById("div1");
var iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT,null, false);
var node = iterator.nextNode();
while (node !== null) {
    alert(node.tagName);
    node = iterator.nextNode();
}
//只返回遍历中遇到的<li>元素,使用一个过滤器
var div = document.getElementById("div1");
var filter = function(node){
    return node.tagName.toLowerCase() == "li" ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
};
var iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT, filter, false);
var node = iterator.nextNode();
while (node !== null) {
    alert(node.tagName);
    node = iterator.nextNode();
}

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

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

 

使用 document.createTreeWalker()方法创建 TreeWalker 对象,接受的 4 个参数 与 document.createNodeIterator()相同。

//不定义过滤器,也可以取得所有<li>元素
var div = document.getElementById("div1");
var walker = document.createTreeWalker(div, NodeFilter.SHOW_ELEMENT, null, false);
walker.firstChild();//转到<p>
walker.nextSibling();//转到<ul>
var node = walker.firstChild();//转到第一个<li>
while (node !== null) { alert(node.tagName);
node = walker.nextSibling();
}

14.“DOM2 级遍历和范围”模块定义了“范围”(range)接口。通过范围可以选择文档中的一个区域,而不必考虑节点的界限(选择在后台完成,对用户是不可见的)。 在常规的 DOM 操作不能更有效地修改文档时,使用范围往往可以达到目的。

(1)使用 createRange()来创建 DOM 范围,每个范围由一个 Range 类型的实例表示,这个实例拥有很多属性和方法,下列属性提供了当前范 围在文档中的位置信息:

  • startContainer:包含范围起点的节点(即选区中第一个节点的父节点)。
  • startOffset:范围在 startContainer 中起点的偏移量。如果 startContainer 是文本节 点、注释节点或 CDATA 节点,那么 startOffset 就是范围起点之前跳过的字符数量。否则,startOffset 就是范围中第一个子节点的索引。
  • endContainer:包含范围终点的节点(即选区中最后一个节点的父节点)。
  • endOffset:范围在 endContainer 中终点的偏移量(与 startOffset 遵循相同的取值规则)。
  • commonAncestorContainer:startContainer 和 endContainer 共同的祖先节点在文档树中位置最深的那个。

(2)使用 selectNode()或 selectNodeContents()来选择文档中的一部分,两个函数都接受一个参数,即一个 DOM 节点,然后使用该节点中的信息来填充范围,selectNode()方法选择整个节点,包括其子节点;selectNodeContents()方法只选择节点的子节点。

<!DOCTYPE html>
<html>
    <body>
        <p id="p1"><b>Hello</b> world!</p>
    </body>
</html>

var range1 = document.createRange(),
    range2 = document.createRange(),
    p1 = document.getElementById("p1"); 4
range1.selectNode(p1);//rang1 包含<p/>元素及其所有子元素
range2.selectNodeContents(p1);// rang2 包含<b/>元素、文本节点"Hello"和文本节点"world!"

此外,为了更精细地控制将哪些节点包含在范围中,还可以使用下列方法:

  • setStartBefore(refNode):将范围的起点设置在 refNode 之前,因此 refNode 也就是范围 选区中的第一个子节点。同时会将 startContainer 属性设置为 refNode.parentNode,将startOffset 属性设置为 refNode 在其父节点的 childNodes 集合中的索引。
  • setStartAfter(refNode):将范围的起点设置在 refNode 之后,因此 refNode 也就不在范 围之内了,其下一个同辈节点才是范围选区中的第一个子节点。同时会将 startContainer 属 性设置为 refNode.parentNode,将 startOffset 属性设置为 refNode 在其父节点的childNodes 集合中的索引加 1。
  • setEndBefore(refNode):将范围的终点设置在 refNode 之前,因此 refNode 也就不在范围之内了,其上一个同辈节点才是范围选区中的最后一个子节点。同时会将 endContainer 属性设置为 refNode.parentNode,将 endOffset 属性设置为 refNode 在其父节点的 childNodes集合中的索引。
  • setEndAfter(refNode):将范围的终点设置在 refNode 之后,因此 refNode 也就是范围选区中的最后一个子节点。同时会将 endContainer 属性设置为 refNode.parentNode,将endOffset 属性设置为 refNode 在其父节点的 childNodes 集合中的索引加 1。

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

<!DOCTYPE html>
<html>
    <body>
        <p id="p1"><b>Hello</b> world!</p>
    </body>
</html>
//选择 HTML 代码中从"Hello"的"llo"到"world!"的"o"
//取得所有节点的引用
var p1 = document.getElementById("p1"),
    helloNode = p1.firstChild.firstChild,
    worldNode = p1.lastChild;

var range = document.createRange();
//setStart()中传入 helloNode 的同时,传入了偏移量 2(即"e"的下一个位置;"H"的位置是 0)。
range.setStart(helloNode, 2);
//setEnd() 中传入 worldNode 的同时传入了偏移量 3,表示选区之外的第一个字符的位置,这个字符是"r",它的 位置是 3(位置 0 上还有一个空格)。
range.setEnd(worldNode, 3);

(4)在创建范围时 ,内部会为这个范围创建一个文档片段,范围所属的全部节点都被添加到了这个文档片段中。创建了范围之后,就可以使用各种方法对范围的内容进行操作了(注意,表示范围的内部文档片段中的所有节点,都只是指向文档中相应节点的指针)。

  • deleteContents():从文档中删除范 围所包含的内容。
  • extractContents():从文档中移除范围选区,返回范围的文档片段。利用这个返回的值,可以将范围的内容插入到文档中的其他地方。
  • cloneContents():创建范围对象的一个副本

(5)插入 DOM 范围中的内容:

<span style="color: red">Inserted text</span>
  • insertNode() 方法:向范围选区的开始处插入一个节点,用来插入一些帮助提示信息,例如在打开新窗口的链接旁边插入一幅图像。
  • var p1 = document.getElementById("p1"),
        helloNode = p1.firstChild.firstChild,
        worldNode = p1.lastChild,
        range = document.createRange();
    
    range.setStart(helloNode, 2);
    range.setEnd(worldNode, 3);
    
    var span = document.createElement("span");
    span.style.color = "red"; 
    span.appendChild(document.createTextNode("Inserted text")); 
    range.insertNode(span);
    
    //结果
    <p id="p1"><b>He<span style="color: red">Inserted text</span>llo</b> world</p>
  • surroundContents()方法:环绕范围插入内容,使用这种技术来突出显示网页中的某些词句。
  • var p1 = document.getElementById("p1"),
        helloNode = p1.firstChild.firstChild,
        worldNode = p1.lastChild,
        range = document.createRange();
    range.selectNode(helloNode);
    var span = document.createElement("span");
    span.style.backgroundColor = "yellow";
    range.surroundContents(span);
    //给范围选区加上一个黄色的背景
    <p><b><span style="background-color:yellow">Hello</span></b> world!</p>

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

(7)使用 compareBoundaryPoints()方法来确定多个范围是否有公共的边界(起点或终点),接受两个参数:表示比较方式的常量值和要比较的范围。表示比较方式的常量值如下:

  • Range.START_TO_START(0):比较第一个范围和第二个范围的起点;
  • Range.START_TO_END(1):比较第一个范围的起点和第二个范围的终点; 
  • Range.END_TO_END(2):比较第一个范围和第二个范围的终点;
  • Range.END_TO_START(3):比较第一个范围的终点和第一个范围的起点。

可能的返回值如下:

  • 如果第一个范围中的点位于第二个范围中的 点之前,返回-1;
  • 如果两个点相等,返回 0;
  • 如果第一个范围中的点位于第二个范围中的点之后,返回 1。

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

(9)使用 detach()方法解除对范围的引用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值