JS 11.4 专有扩展

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);