DOM中的范围

DOM2级遍历和范围模块定义了范围(range),通过范围可以选择文档中的一个区域,而不必考虑节点的界限。在常规的DOM操作不能有效地修改文档时,使用范围往往可以达到目的。

<!DOCTYPE html>
<html>
    <body>
        <p id="p1"><b>Hello</b> world!</p>
    </body>
</html>

1.创建范围

const range = document.createRange();

每一个范围由一个Range类型的实例表示,Range拥有以下属性:

startContainer: 包含范围起点的节点(选中区第一个节点的父节点)

startOffset: 范围在startContainer中的偏移量

endContainer: 包含范围终点的节点(选中区最后一个节点的父节点)

endOffset: 范围在endContainer中的偏移量

commonAncestorContainer: startContainer和endContainer共同的祖先节点在文档树种位置最深的那个

2.用DOM范围实现简单选择

使用范围选择文档中的一部分,最简单的方式就是使用selectNode或selectNodeContents,这两个方法接受一个DOM节点作为参数。selectNode方法会选择整个节点(包括子节点),selectNodeContents方法只选择节点的子节点。

const range1 = document.createRange();
const range2 = document.createRange();
const p1 = document.querySelector("#p1");

range1.selectNode(p1);                     // 选中<p id="p1"><b>Hello</b> world!</p>
range2.selectNodeContents(p1);             // 选中<b>Hello</b> world!

3.用DOM范围实现复杂选择

要创建复杂选择就需要用setStart和setEnd方法。这两个方法都接受两个参数:一个参照节点和一个偏移量。对于setStart来说,参照节点会变成startContainer,偏移量会变成startOffset。对于setEnd来说,参照节点会变成endCOntainer,偏移量会变成endOffset。

const p1 = document.querySelector("#p1");
const range = document.createRange();
const helloNode = p1.firstChild.firstChild;
const worldNode = p1.lastChild;

// 选区从"Hello"的"e"后面开始,到" world!"的"r"之前结束
range.setStart(helloNode, 2);
range.setEnd(worldNode, 3); 

4.删除DOM范围中的内容

想要从文档中删除范围所包含的内容就需要用到deleteContents方法。

const p1 = document.querySelector("#p1");
const range = document.createRange();
const helloNode = p1.firstChild.firstChild;
const worldNode = p1.lastChild;

// 选区从"Hello"的"e"后面开始,到" world!"的"r"之前结束
range.setStart(helloNode, 2);
range.setEnd(worldNode, 3); 

// 页面html会变成"<p id="p1"><b>He</b>rld!</p>"
range.deleteContents();

使用extractContents方法可以达到同样的效果,但区别在于它会返回删除的文档范围片段。利用这个返回值,可以将范围的内容插入到文档的其他地方。

const p1 = document.querySelector("#p1");
const range = document.createRange();
const helloNode = p1.firstChild.firstChild;
const worldNode = p1.lastChild;

// 选区从"Hello"的"e"后面开始,到" world!"的"r"之前结束
range.setStart(helloNode, 2);
range.setEnd(worldNode, 3); 

// 页面html会变成"<p id="p1"><b>He</b>rld!</p>"
const fragment = range.extractContents();
p1.parentNode.appendChild(fragment);

另外一种做法,使用cloneContents方法创建范围的一个副本,然后再文档的其他地方插入该副本。

const p1 = document.querySelector("#p1");
const range = document.createRange();
const helloNode = p1.firstChild.firstChild;
const worldNode = p1.lastChild;

// 选区从"Hello"的"e"后面开始,到" world!"的"r"之前结束
range.setStart(helloNode, 2);
range.setEnd(worldNode, 3); 

// 页面html会变成"<p id="p1"><b>He</b>rld!</p>"
const fragment = range.cloneContents();
p1.parentNode.appendChild(fragment);

 5.插入DOM范围中的内容

使用insertNode方法可以向范围选区的开始处插入一个节点。

const p1 = document.querySelector("#p1");
const range = document.createRange();
const helloNode = p1.firstChild.firstChild;
const worldNode = p1.lastChild;

// 选区从"Hello"的"e"后面开始,到" world!"的"r"之前结束
range.setStart(helloNode, 2);
range.setEnd(worldNode, 3); 

// 页面html会变成
// <p id="p1"><b>He<span style="color: red">Inserted text</span>llo</b> world!</p>"
const span = document.createElement("span");
span.style.color = "red";
span.appendChild(document.createTextNode("Inserted text"));
range.insertNode(span);

6. 折叠DOM范围

所谓折叠范围,就是指范围中未选择文档的任何部分。在折叠范围时,光标的位置会落在文档中的两个部分之间,可能是范围选区的开始位置,也可能是结束位置。

使用collapse方法来折叠范围,这个方法接受一个布尔值作为参数,表示折叠到范围的那一端,true表示折叠到范围的起点,false表示折叠到范围的终点。要确定范围是否已经折叠完毕,可以检查collapsed属性。

range.collapse(true);            // 折叠到起点
alert(range.collapsed);          // 输出true

检测某个范围是否处于折叠状态,可以帮助我们确定范围中的两个节点是否相邻。

<p id="p1">Paragraph 1</p><p id="p2">Paragraph 2</p>
const p1 = document.querySelector("#p1");
const p2 = document.querySelector("#p2");
const range = document.createRange();

range.setStartAfter(p1);
range.setEndBefore(p2);
alert(range.collapsed);                  // 输出true

7.比较DOM范围

在有多个范围的情况下,可以使用compareBoundaryPoints方法来确定这些范围是否有公共的边界。这个方法接受两个参数:表示比较方式的常量值和要比较的范围。表示比较方式的常量值如下:

Range.START_TO_START(0):比较第一个范围和第二个范围的起点

Range.START_TO_END(1):比较第一个范围的起点和第二个范围的终点

Range.END_TO_END(2):比较第一个范围和第二个范围的终点

Range.END_TO_START(3):比较第一个范围的终点和第二个范围的起点

compareBoundaryPoints方法可能的返回值如下:

如果第一个范围中的点位于第二个范围中的点之前,则返回-1

如果第一个范围中的点第二个范围中的点相等,则返回0

如果第一个范围中的点位于第二个范围中的点之后,则返回1

const p1 = document.querySelector("#p1");
const range1 = document.createRange();
cosnt range2 = document.createRange();

range1.selectNodeContents(p1);
range2.selectNodeContents(p1);
range2.setEndBefore(p1.lastChild);

alert(range1.compareBoundaryPoints(Range.START_TO_START, range2);        // 0
alert(range1.compareBoundaryPoints(Range.END_TO_END, range2);            // 1

8.清理DOM范围

在使用玩范围之后,最好调用detach方法,以便从创建范围的文档中分离该范围。调用detach方法后,就可以放心的解除对范围的引用,从而让垃圾回收机制回收其内存。

range.detach();         // 从文档中分离
range = null;           // 解除引用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值