你不知道的那些DOM

DOM变化

DOM2级和3级的目的在于扩展DOM API,以满足操作XML的所有需求,同时提供更好的错误处理及特性检测能力。从某种意义上讲,实现这一目的的很大程度意味着对命名空间的支持。

var supportsDOM2Core = document.implementation.hasFeature('Core', '2.0');

var supportsDOM3Core = document.implementation.hasFeature('Core', '3.0');

var supportsDOM2HTML = document.implementation.hasFeature('HTML', '2.0')

var supportsDOM2Views = document.implementation.hasFeature('Views', '2.0');

var supportsDOM2XML = document.implementation.hasFeature('XML', '2.0')
复制代码

针对XML命名空间的变化

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

命名空间要使用xmlns特性来指定。

<html xmlns='http://www.w3.org/1999/xhtml'>
    <head>
        <title>Example XHTML page</title>
    </head>
    <body>
        Hello world!
    </body>
</html>
复制代码
Node类型的变化

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

  • localName: 不带命名空间前缀的节点名称
  • namespaceURI: 命名空间URI或者(在未指定的情况下是)null
  • prefix: 命名空间前缀或者(未指定的情况下是)null

其他方面的变化

DOM的其他部分在‘DOM2级核心’中也发生了一些变化。这些变化与XML命名空间无关,而是更倾向于确保API的可靠性及完整性。

DocumentType类型的变化

新增了3个属性:publicId、systemId和internalSubset。

Document类型的变化

Document类型的变化中唯一与命名空间无关的方法是importNode()。

需要注意的是,每个节点都有一个ownerDocument属性,表示所属的文档。如果调用appendChild()时传入的节点属于不同的文档(ownerDocument属性的值不一样),则会导致错误。但在调用importNode()时传入不同文档的节点则会返回一个新节点,这个新节点的所有权归当前文档所有。

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

var newNode = document.importNode(oldNode, true);  //导入节点及其子节点

document.body.appendChild(newNode);
复制代码
Node类型的变化

Node类型中唯一与命名空间无关的变化,就是添加了isSupported()方法。与DOM1级为document.implementation引入的hasFeature()方法类似,isSupported()方法用于确定当前节点具有什么能力。

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

var div1 = document.createElement('div');

div1.setAttribute('class', 'box');

var div2 = docuemnt.createElement('div');

div2.setAttribute('class', 'box');

div1.isSameNode(div1);  // true
div1.isSameNode(div2); // false
div1.isEqualNode(div2); // true
复制代码
框架的变化

样式

在HTML中定义样式的方式有3种:通过<link/>元素包含外部样式表文件、使用<style/>元素定义嵌入式样式,以及使用style特性定义针对特定元素的样式。

DOM2级样式模块围绕这3种应用样式的机制提供了一套API。

访问元素的样式

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

对于短划线的CSS属性名,必须将其转换成驼峰大小写形式,才能通过JavaScript访问。

  • background-image -> style.backgroundImage
  • font-family -> style.fontFamily

其中一个不能直接转换的CSS属性就是float。由于float是JavaScript中的保留字,因此不能用作属性名。规定对应的属性名是cssFloat。而IE中则是styleFloat。

DOM样式属性和方法

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

  • cssText
  • length
  • parentRule
  • getPropertyCSSValue(propertyName)
  • getPropertyPriority(propertyName)
  • getPropertyValue(propertyName): 返回给定属性的字符串值
  • item(index): 返回给定位置的CSS属性的名称
  • removeProperty(propertyName):从样式中删除给定属性。
  • setProperty(propertyName, value, priority)

设置cssText是为元素应用多项变化最快捷的方式:

myDiv.style.cssText = 'width: 25px; height: 100px'
复制代码

迭代CSS属性:

var prop, value, i, len;

for (i = 0; len = myDiv.style.length; i < len; i++) {
    prop = myDiv.style[i];  //或者 myDiv.style.item(i)
    
    value = myDiv.style.getPropertyValue(prop);
    
    console.log(prop + ' : ' + value)
}
复制代码
计算的样式

getComputedStyle()方法。这个方法接受两个参数:要取得计算样式的元素和一个伪元素字符串。如果不需要伪元素信息,第二个参数可以是null。

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

var computedStyle = myDiv.computedStyle // IE环境下 myDiv.currentStyle
复制代码

这个属性是CSSStyleDeclaration的实例。

操作样式表

CSSStyleSheet对象是一套只读的接口(有一个属性例外)。使用下面的代码可以确定浏览器是否支持DOM2级样式表。

var supportDOM2StyleSheets = dcoument.implementation.hasFeature('StyleSheets', '2.0');
复制代码

CSSStyleSheet继承自StyleSheet,后者可以作为一个基础接口来定义非CSS样式表。从StyleSheet接口继承而来的属性如下。

  • disabled: 表示样式表是否被禁用的布尔值。
  • href:如果样式表是通过包含的,则是样式表的URL,否则是null
  • media:当前样式表支持的所有媒体类型的集合
  • ownerNode: 指向拥有当前样式的节点的指针,样式表可能是在HTML中通过<link><style/>引入的。如果当前样式表是其他样式表通过@import导入的,则这个属性值为null。IE不支持这个属性。
  • parentStyleSheet: 在当前样式表通过@import导入的情况下,这个属性是一个指向导入它的样式表的指针。
  • title: ownerNode中title属性的值。
  • type:表示样式表类型的字符串。对CSS样式表而言,这个字符串是'text/css'。
  • cssRules:样式表中包含的样式规则的集合。IE中类似的是rules属性。
  • ownerRule:如果样式表是通过@import导入的,这个属性就是一个指针,指向表示导入的规则;否则值为null。
  • deleteRule(index):删除cssRules集合中指定位置的规则。
  • insertRule(rule, index):向cssRules集合中指定的位置插入rule字符串。

应用于文档的所有样式表是通过document.styleSheets集合来表示的。

var sheet = null;

for (var i = 0, len = document.styleSheets.length; i < len; i++) {
    sheet = document.styleSheets[i];
    console.log(sheet.href)
}

复制代码

元素大小

偏移量

offset dimension,包括元素在屏幕上占用的所有可见的空间。通过下面四个属性可以取得元素的偏移量。

  • offsetHeight
  • offsetWidth
  • offsetLeft
  • offsetTop

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

元素,因为是在DOM层次中距
最近的一个具有大小的元素。

function getElementOffsetLeft (element) {
   var currentLeft = element.offsetLeft;
   
   var parent = element.offsetParent;
   
   while (parent) {
       currentLeft += parent.offsetLeft;
       parent = parent.offsetParent;
   }
   
   return currentLeft;
}

同理 // top
复制代码
客户区大小 client dimension

是指元素内容及其内边距所占据的空间大小(content + padding)。

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

常见用法:确定浏览器视口大小。

function getViewport () {
    if (document.compatMode == 'BackCompat') {
        return {
            width: document.body.clientWidth,
            height: document.body.clientHeight
        }
    } else {
        return {
            width: document.documentElement.clentWidth,
            height: document.documentElement.clientHeight
        }
    }
}
复制代码
滚动大小(scroll dimension)

指的是包含滚动内容的元素的大小。

4个与滚动大小相关的属性:

  • scrollHeight: 在没有滚动条的情况下,元素内容的总高度。
  • scrollWidth: 在没有滚动条的情况下,元素内容的总宽度。
  • scrollLeft:被隐藏在内容区左侧的像素数。
  • scrollTop: 被隐藏在内容区域上方的像素数。

因为浏览器兼容性的问题,在确定文档的总高度时,必须取得scrollWidth/clientWidth和scrollHeight/clientHeight中的最大值,才能保证在跨浏览器时得到精确的结果。

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

var docWidth = Math.max(document.documentElement.scrollWidth, document.documentElement.clientWidth);
复制代码

遍历

DOM2级遍历和范围模块定义了两个用于辅助完成顺序遍历DOM结构的类型:NodeIterator和TreeWalker

var supportTraversals = document.implementation.hasFeature('Traversal', '2.0');

var supportNodeIterators = (typeof document.createNodeIterator == 'function');

var supportTreeWalker = (typeof document.createTreeWaler == 'function')
复制代码

NodeIterator

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

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

whatToShow参数是一个位掩码,通过应用一或多个filter来确定要访问哪些节点。这个参数的值以常量形式在NodeFilter类型中定义。

  • NodeFilter.SHOW_ALL:显示所有类型的节点。
  • NodeFilter.SHOW_ELEMENT:显示元素节点。
  • NodeFilter.SHOW_ATTRIBUTE:显示特性节点。由于 DOM 结构原因,实际上不能使用这个值。
  • NodeFilter.SHOW_TEXT:显示文本节点。
  • NodeFilter.SHOW_CDATA_SECTION:显示 CDATA 节点。对 HTML 页面没有用。
  • NodeFilter.SHOW_ENTITY_REFERENCE:显示实体引用节点。对 HTML 页面没有用。
  • NodeFilter.SHOW_ENTITYE:显示实体节点。对 HTML 页面没有用。
  • NodeFilter.SHOW_PROCESSING_INSTRUCTION:显示处理指令节点。对 HTML 页面没有用。
  • NodeFilter.SHOW_COMMENT:显示注释节点。
  • NodeFilter.SHOW_DOCUMENT:显示文档节点。
  • NodeFilter.SHOW_DOCUMENT_TYPE:显示文档类型节点。
  • NodeFilter.SHOW_DOCUMENT_FRAGMENT:显示文档片段节点。对 HTML 页面没有用。
  • NodeFilter.SHOW_NOTATION:显示符号节点。对 HTML 页面没有用。

除了NodeFilter.SHOW_ALL之外,可以使用按位或操作符来组合多个选项:

var whatToShow = NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT;
复制代码

可以通过createNodeIterator()方法的filter参数来指定自定义的NodeFilter对象,或者指定一个功能类似节点过滤器(node filter)的函数。

每个NodeFilter对象只有一个方法,即accept-Node();如果应该访问给定的节点,该方法返回NodeFilter.FILTER_ACCEPT,如果不应该访问给定的节点,该方法返回NodeFilter.FILTER_SKIP。由于NodeFilter是一个抽象的类型,因此不能直接创建它的实例。在必要时,只要创建一个包含acceptNode()方法的对象,然后将这个对象传入createNodeIterator()中即可。

var filter = {
    acceptNode: function (node) {
        return node.tagName.toLowerCase() == 'p' ?
        NodeFilter.FILTER_ACCEPT :
        NodeFilter.FILTER_SKIP;
    }
};

var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT, filter, false);
复制代码

第三个参数也可以是一个与acceptNode()方法类似的函数,如下所示。

var filter = function (node) {
   return node.tagName.toLowerCase() == 'p' ?
   NodeFilter.FILTER_ACCEPT :
   NodeFilter.FILTER_SKIP;
};

var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT, filter, false);
复制代码

如果不指定过滤器,那么应该在第三个参数的位置上传入null。

NodeIterator类型的两个主要方法是nextNode()和previousNode()。在刚刚创建的NodeIterator对象中,有一个内部指针指向根节点,因此第一次调用nextNode()会返回根节点。

TreeWalker

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

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

范围

为了让开发人员更方便地控制页面,“DOM2级遍历和范围”模块定义了“范围”(range)接口。通过范围可以选择文档中的一个区域,而不必考虑节点的界限。

DOM中的范围

DOM2级在Document类型中定义了createRange()方法。在兼容DOM的浏览器中,这个方法属于document对象。

var supportsRange = document.implementation.hasFeature('Range', '2.0');

var supportsRange2 = (typeof document.createRange == 'function');
复制代码

如果浏览器支持范围,那么就可以使用createRange()来创建DOM范围。

var range = document.createRange();
复制代码

与节点类似,新创建的范围也直接与创建它的文档关联在一起,不能用于其他文档。

IE8及更早版本中的范围

小结

DOM2级规范定义了一些模块,用于增强DOM1级

  • DOM2级核心为不同的DOM类型引入了一些与XML命名空间有关的方法。还定义了以编程方式创建Document实例的方法,也支持创建DocumentType对象。
  • DOM2级样式模块主要针对操作元素的样式信息而开发,其特性简要总结如下:
    • 每个元素都有一个关联的style对象,乐意用来确定和修改行内的样式。
    • 要确定某个元素的计算样式,可以使用getComputedStyle()方法。
    • IE不支持getCumputedStyle()方法,但提供了currentStyle()方法。
    • 可以通过document.styleSheets集合访问样式表。
    • 除IE之外的所有浏览器都支持针对样式表的这个接口,IE也为几乎所有相应的DOM功能提供了自己的一套属性和方法。
  • DOM2级遍历和范围模块提供了与DOM结构交互的不同方式:
    • 遍历即使用NodeIterator或TreeWalker对DOM执行深度优先的遍历。
    • NodeIterator是一个简单的接口,只允许以一个节点的步幅前后移动。而treeWalker在提供相同功能的同时,还支持在DOM结构的各个方向上移动,包括父节点、同辈节点和子节点等方向。
    • 范围是选择DOM结构中特定部分,然后再执行相应操作的一种手段。
    • 使用范围选区可以在删除文档中某些部分的同时,保持文档结构的格式良好,或者复制文档中的相应部分。
    • IE8及更早版本不支持DOM2级遍历和范围模块,但它提供了一个专有的文本范围对象,可以用来完成简单的基于文本的范围操作。IE9完全支持DOM遍历。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值