11.4 专有扩展
实际上专有扩展为Web开发领域提供了很多重要的功能,这些功能最终都在HTML5规范中得到了标准化;
这个小节好像是讲,在写这本书的时候还没有被标准化的DOM扩展;
文档模式
IE8引入了一个新的概念叫文档模式;
页面的文档模式决定了可以使用什么功能;
换句话说,文档模式决定了你可以使用哪个级别的CSS,
可以在JavaScript中使用哪些API,以及如何对待文档类型(doctype);
要强制浏览器以某种模式渲染页面,可以使用HTTP头部信息X-UA-Compatible,或通过等价的<meta>
标签来设置;
<meta http-equiv="X-UA-Compatible" content="IE=IEVersion">
通过document.documentMode属性可以知道给定页面使用的是什么文档模式;
这个属性是IE8中新增的,它会返回使用的文档模式的版本号(在IE9 中,可能返回的版本号为5、7、8、9);
children属性
由于IE9之前的版本与其他浏览器在处理文本节点中的空白符时有差异,因此就出现了children属性;
这个属性是HTMLCollection的实例,只包含元素中同样还是元素的子节点;
除此之外,children属性与childNodes没有什么区别,
即在元素只包含元素子节点时,这两个属性的值相同;
contains()方法
调用contains()方法的应该是祖先节点,也就是搜索开始的节点,
这个方法接收一个参数,即要检测的后代节点。如果被检测的节点是后代节点,
该方法返回true,否则,返回false;
alert(document.documentElement.contains(document.body)); //true
使用DOM Level3 compareDocumentPosition()也能确定节点间的关系,返回一个表示该关系的位掩码;
1 | 无关 |
2 | 居前 |
4 | 居后 |
8 | 包含 |
16 | 被包含 |
例子;
var result = document.documentElement.compareDocumentPosition(document.body);
alert(!!(result & 16));
执行上面的代码后,result会变成20(表示“居后”的4 加上表示“被包含”的16);
对掩码16执行按位操作会返回一个非零数值,而两个逻辑非操作符会将该数值转换成布尔值;
还记得吧两个!!强转布尔值以及非0数字都是true吧(
一个通用的contains()例子;
function contains(refNode, otherNode) {
if (typeof refNode.contains == "function" &&
(!client.engine.webkit || client.engine.webkit >= 522)) {
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;
}
}
首先检测refNode中是否存在contains()方法(能力检测),更详细的能力检测介绍page319;
接下来检查是否存在compareDocumentPosition()方法,
而函数的最后一步则是自otherNode开始向上遍历DOM结构,
以递归方式取得parentNode,并检查其是否与refNode相等;
在文档树的顶端,parentNode的值等于null,于是循环结束;
插入文本
IE原来专有的插入标记的属性innerHTML和outerHTML已经被HTML5纳入规范;
还有两个没有被HTML5看中的属性,innerText和outerText;
innerText属性
例子;
<div id="content">
<p>This is a <strong>paragraph</strong> with a list following it.</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
对于这个div来说,innerText属性会返回如下内容
This is a paragraph with a list following it.
Item 1
Item 2
Item 3
不同浏览器处理空白符的方式不同,因此输出的文本可能会也可能不会包含原始HTML代码中的缩进;
接下来,如果;
div.innerText = "Hello world!";
那么;
<div id="content">Hello world!</div>
这玩意跟innerHTML有区别吗,把子节点全部移除了重新写入文本啊??
另一个例子,使用这个属性过滤HTML标签;
div.innerText = div.innerText;
执行这行代码后,就用原来的文本内容替换了容器元素中的所有内容(包括子节点,因而也就去掉了HTML标签);
兼容的例子;
function getInnerText(element){
return (typeof element.textContent == "string") ?
element.textContent : element.innerText;
}
function setInnerText(element, text){
if (typeof element.textContent == "string"){
element.textContent = text;
} else {
element.innerText = text;
}
}
然而也没有完全兼容;
innerText 与textContent返回的内容并不完全一样;
比如,innerText会忽略行内的样式和脚本,而textContent则会像返回其他文本一样返回行内的样式和脚本代码;
避免跨浏览器兼容问题的最佳途径,就是从不包含行内样式或行内脚本的DOM子树副本或DOM片段中读取文本;
outerText属性
在读取文本值时,outerText与innerText的结果完全一样;
但在写模式下,outerText 就完全不同了:
outerText 不只是替换调用它的元素的子节点,而是会替换整个元素(包括子节点);
我们也建议读者尽可能不要使用这个属性;2333
滚动
下面列出的几个方法都是对HTMLElement类型的扩展,因此在所有元素中都可以调用;
1.scrollIntoViewIfNeeded(alignCenter)
只在当前元素在视口中不可见的情况下,才滚动浏览器窗口或容器元素,最终让它可见;
如果当前元素在视口中可见,这个方法什么也不做;
如果将可选的alignCenter参数设置为true,则表示尽量将元素显示在视口中部(垂直方向);
Safari和Chrome实现了这个方法;
2.scrollByLines(lineCount)
将元素的内容滚动指定的行高,lineCount值可以是正值,也可以是负值;
Safari和Chrome实现了这个方法;
3.scrollByPages(pageCount)
将元素的内容滚动指定的页面高度,具体高度由元素的高度决定;
Safari和Chrome实现了这个方法;
scrollIntoView()和scrollIntoViewIfNeeded()的作用对象是元素的容器;
而scrollByLines()和scrollByPages()影响的则是元素自身;
//将页面主体滚动5 行
document.body.scrollByLines(5);
//在当前元素不可见的时候,让它进入浏览器的视口
document.images[0].scrollIntoViewIfNeeded();
//将页面主体往回滚动1 页
document.body.scrollByPages(-1);