12.4 范围
为了让开发人员更方便的控制页面,“DOM2级遍历和范围”模块定义了“范围”(range)接口。通过范围可以选择文档中的一个区域,而不必考虑节点的界限(选择在后台完成,对用户是不可见的。)在常规的DOM操作不能更有效的修改文档时,使用范围往往可以达到目的。
12.4.1 DOM中的范围
DOM2级在Document类型中定义了createRange()方法。在兼容DOM的浏览器中,这个方法属于document对象。使用hasFeature()或者直接检测该方法都可以确定浏览器是否支持范围。
如果支持就可以使用createRang()来创建DOM范围:
var range = document.createRange();
与节点类似,新创建的范围也应该与创建它的文档关联在一起,不能用于其他文档。创建了范围之后,接下来就可以使用它在后台选择文档中的特定部分。
而创建范围并设置了其位置之后,还可以针对范围的内容执行很多种操作,从而实现对底层DOM树的更精细的控制。
每个范围由一个Range类型的实例标识,这个实例拥有很多属性和方法。在把范围放到文档中特定的位置时,这些属性都会被赋值:
1、用DOM范围实现简单选择
要使用范围来选择文档中的一部分,最简单的方式就是使用selectNode()或selectNodeContents()。这两个方法都接受一个参数,即一个DOM节点,然后使用该节点中的信息来填充范围。
◆ selectNode()方法选择整个节点,包含其子节点
◆ selectNodeContents()方法则只选择节点的子节点
<!DOCTYPE>
<html>
<body>
<p id="p1"><b>Hello</b></p>
</body>
<script type="text/javascript">
var range1 = document.createRange();//rang1包含<p/>元素及其所有子元素
range2 = document.createRange();//rang2包含<br/>元素、文本节点“Hello”和文本节点"world"
p1 = document.getElementById("p1");
range1.selectNode(p1);
range2.selectNodeCounts(p1);
</script>
</html>
image.png
2、用DOM范围实现复杂选择
要创建复杂的范围就得使用setStart()和setEnd()方法。
这两个方法都接受两个参数:一个参照节点和一个偏移量值。
◆ setStart():参照节点会变成startContainer,而偏移量值会变成startOffset
◆ setEnd():参照节点会变成endContainer,而偏移量值会变成endOffset。
3、操作DOM范围中的内容
◆ deleteContents():这个方法能够从文档中删除范围所包含的内容
◆ extractContents():与deleteContents方法相似,也会从文档中移除范围选取。但这两个方法的区别在于,extractContents()会返回范围的文档片段。利用这个返回的值,可以将范围的内容插入到文档中的其他地方。
◆ cloneContents():使用此方法创建范围对象的一个副本,然后在文档的其他地方出入该副本。与extractContents()类似,都返回文档片段。主要的区别在于,cloneContents返回的文档片段包含的是范围中节点的副本,而不是实际的节点。
4、插入DOM范围中的内容
使用insertNode()方法可以向范围选取的开始处插入一个节点
5、折叠DOM范围
所谓折叠范围,就是指范围中未选择文档的任何部分。可以用文本框来描述折叠范围的过程。
使用collapse()方法来折叠范围,这个方法接收一个参数,一个布尔值,表示要折叠到范围的哪一端。参数true表示折叠范围的起点,false表示终点。要确定范围已经折叠完毕,可以检查collapsed属性。
range.collapse(true);//折叠到起点
alert(range.collapsed);//输出true
6、比较DOM范围
在多个范围的情况下,使用compareBoundaryPoints()方法来确定这些范围是否有公共的边界(起点或终点)
这个方法接受两个参数:表示比较方式的常量值和要比较的范围。
7、复制DOM范围
使用cloneRange()方法复制范围。这个方法会创建调用它的范围的一个副本
var newRange=range.cloneRange();
//新创建的范围与原来的范围包含相同的属性,而修改它的端点不会影响到原来的范围
8、清理DOM范围
调用dach()方法,以便从创建范围的文档中分离出该范围。
调用detach()之后,就可以放心的解除对范围的引用,从而让垃圾回收机制回收其内存了。
range.detach();//从文档中分离
range=null;//解除引用。
//一旦分离范围,就不能再恢复使用了。
————————————————————————————————
global对象
ES5的顶层对象,本身也是一个问题,因为它在各种实现里面是不统一的。
◆ 浏览器里面,顶层对象是window,但Node和Web Worker没有window。
◆ 浏览器和Web Worker里面,self也指向顶层对象,但是Node没有self。
◆ Node里面,顶层对象是global,但其他环境都不支持。
为了能在各种环境中,同段代码能取到顶层对象,一般使用this变量,但是有局限性。
◆ 全局环境中,this会返回顶层对象。但是,Node模块和ES6模块中,this返回的是当前模块
◆ 函数里面的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象。但是,严格模式下,这时this会返回undefined
◆ 不管是严格模式,还是普通模式,new Function(‘return this’)(),总是会返回全局对象。但是,如果浏览器使用了CSP(Content Security Policy,内容安全策略。),那么eval、new Function这些方法都可能无法使用。
综上所述,很难找到一种方法,可以在所有情况下,都取到顶层对象。
有一提案,在语言标准的层面,引入global作为顶层对象。也就是说,在所有环境下,global都是存在的,都可以从它拿到顶层对象。
//CommonJS的写法
var global = require('system.global')();
//ES6 模块的写法
import getGlobal from 'system.global';
const global=getGlobal();
//上面代码将顶层对象放入变量global
网友评论