上一节我们学习了"[JavaScript学习]JavaScript事件-HTML事件"。这节主要学习"JavaScript文档对象模型-DOM扩展"。
根据W3C对DOM的要求,浏览器可以自行为它添加属性和方法,以增强其功能。新增加的部分功能是为了向后兼容,而另外一些功能则是根据开发人员的反馈,这对常见问题而添加的。
呈现模式
从IE6开始,IE浏览器区分标准模式和混杂模式,这就需要我们在使用的时候区分浏览器处于何种模式下。IE为document对象添加了一个名为compatMode
的属性,这个属性的唯一任务就是识别浏览器处于什么模式下。例如下面的例子,如果是标准模式,则document.compatMode
的值等于"CSS1Compat";如果是混杂模式,document.compatMode
的值等于"BackCompat"。
if(document.compatMode == "CSS1Compat"){
alert("标准模式");
}else{
alert("混杂模式");
}
在IE之后,Firefox、Chrome和Opera浏览器也都实现了这个属性。Safari浏览器从3.1版本开始实现document.compatMode
属性。
后来,IE8又为document
对象引入一个名为documentMode
的新属性。它的用法如下所示。
if(document.compatMode > 7){
alert("IE8+ 标准模式");
}
这是因为IE8有3种不同的呈现模式,引入这个属性正是为了区分这些模式。这个属性的值如果是5,则表示混杂模式(即IE5模式),如果值为7,则表示IE7仿真模式,如果是8,则表示IE8标准模式。
contains()方法
我们在操作DOM的时候经常需要判断某个给定的节点是不是另外一个节点的后代节点。IE浏览器最先引入了一个contains()
方法,该方法可以在不遍历整个DOM树的情况下就可获取该信息。contains()
方法应该在作为搜索起点的祖先节点上调用,该方法接收一个参数,即要检测的后代节点。如果传入的节点是当前节点的后代,那么会返回true
,否则返回false
。例如:
alert(document.documentElement.contains(document.body)); //true
上面的例子测试<body>
元素是不是<html>
元素的后代,如果是格式正确的HTML页面,那么它会返回true
。
IE,Safari3+,Opera8+和Chrome浏览器都支持contains()
方法。
Firefox浏览器不支持contains()
方法,但是Firefox在DOM3级中实现了一个替代的方法:compareDocumentPosition()
方法。(Opera9.5+的浏览器也支持该方法)。这个方法用于确定两个节点之间的关系,返回一个表示该关系的位掩码(bitmark)。下表中列出了这个位掩码的值。
| 掩码 | 节点关系 | |----|-------------------------| | 1 | 无关(给定的节点不在当前文档中) | | 2 | 居前(给定的节点在DOM树中位于参考节点之前) | | 4 | 居后(给定的节点在DOM树中位于参考节点之后) | | 8 | 包含(给定的节点是参考节点的祖先) | | 16 | 被包含(给定的节点是参考节点的后代) |
如果需要模仿contains()
方法,那么应该要关注的是掩码16。可以对compareDocumentPosition()
方法的结果执行按位与操作,以确定参考节点(调用compareDocumentPosition()
方法的当前节点)是否包含给定的节点(作为参数传入的节点)。例如下面的例子:
var result = document.documentElement.compareDocumentPosition(document.body);
console.info("result="+result);
console.info("按位与操作后的布尔值结果为:"+!!(result & 16));
上面的代码在执行compareDocumentPosition()
方法后,得到的结果为20,表示"居后"的4和"被包含"的16。然后对掩码16进行按位与操作会返回一个非零数值。两个逻辑非操作符的作用是将数值转换为布尔值类型。
我们可以通过浏览器的能力检测来编写一个通用的contains()
函数。
/*********************************************************/
/* 浏览器通用contains()方法
/* 参数:refNode - 参考节点 */
/* 参数:otherNode - 要检测的节点 */
/* 返回值: refNode包含otherNode是返回true,否则返回false*/
/*********************************************************/
function contains(refNode,otherNode){
if(typeof refNode.contains == "function"){
return refNode.contains(otherNode);
}else if(typeof refNode.compareDocumentPosition == "function"){
return !!(refNode.compareDocumentPosition(otherNode) & 16);
}else{
var node = otherNode.parentNode;
do{
if (node === refNode) {
return true;
}else{
node = node.parentNode;
}
}while(node !== null);
return false;
}
}
这个通用contains()
函数使用3种方法来确定某个节点是不是另外一个节点的后代节点。函数的第一个参数是参考节点,第二个参数是要检测的节点。
在函数体内,首先检测refNode中是否存在contains()
方法,接下来检测是否有compareDocumentPosition()
方法,函数的最后一步是从otherNode开始向上遍历DOM树,递归获取parentNode并检查是否和refNode相等。在文档树的顶端,parentNode的值等于null,于是循环结束。