上一节介绍了移除和复制范围的内容,本节来看一看怎么向范围中插入内容。使用 insertNode() 方法可以在范围选区的开始位置插入一个节点。例如,假设我们想在前面例子中的 HTML 中插入如下 HTML:
<span style="color: red">Inserted text</span>
可以使用下列代码:
let p1 = document.getElementById("p1"),
helloNode = p1.firstChild.firstChild,
worldNode = p1.lastChild,
range = document.createRange();
range.setStart(helloNode, 2);
range.setEnd(worldNode, 3);
let span = document.createElement("span");
span.style.color = "red"; span.appendChild(document.createTextNode("Inserted text")); range.insertNode(span);
注意,正好插入到"Hello"中的"llo"之前,也就是范围选区的前面。同时,也要注意原始
的 HTML 并没有添加或删除元素,因为这里并没有使用之前提到的方法。使用这个技术可以插入有 16 用的信息,比如在外部链接旁边插入一个小图标。
除了向范围中插入内容,还可以使用 surroundContents()方法插入包含范围的内容。这个方法 接收一个参数,即包含范围内容的节点。调用这个方法时,后台会执行如下操作:
运行上面的代码会得到如下 HTML 代码:
<p id="p1"><b>He<span style="color: red">Inserted text</span>llo</b> world</p>
- (1) 提取出范围的内容;
- (2) 在原始文档中范围之前所在的位置插入给定的节点; (3) 将范围对应文档片段的内容添加到给定节点。 这种功能适合在网页中高亮显示某些关键词,比如:
let p1 = document.getElementById("p1"),
helloNode = p1.firstChild.firstChild, 19 worldNode = p1.lastChild,
range = document.createRange();
range.selectNode(helloNode);
let span = document.createElement("span");
span.style.backgroundColor = "yellow";
range.surroundContents(span);
执行以上代码会以黄色背景高亮显示范围选择的文本。得到的 HTML 如下所示:
<p><b><span style="background-color:yellow">Hello</span></b> world!</p>
为了插入元素,范围中必须包含完整的 DOM 结构。如果范围中包含部分选择的非文节点, 22 这个操作会失败并报错。另外,如果给定的节点是 Document、DocumentType 或 DocumentFragment 类型,也会导致抛出错误。
如果范围并没有选择文档的任何部分,则称为折叠(collapsed)。折叠范围有点类似文本框:如果 文本框中有文本,那么可以用鼠标选中以高亮显示全部文本。这时候,如果再单击鼠标,则选区会被移 24 除,光标会落在某两个字符中间。而在折叠范围时,位置会被设置为范围与文档交界的地方,可能是范 围选区的开始处,也可能是结尾处。图 16-10 展示了范围折叠时会发生什么。
折叠范围可以使用 collapse()方法,这个方法接收一个参数:布尔值,表示折叠到范围哪一端。 true 表示折叠到起点,false 表示折叠到终点。要确定范围是否已经被折叠,可以检测范围的 collapsed 属性:
range.collapse(true); // 折叠到起点 console.log(range.collapsed); // 输出true
测试范围是否被折叠,能够帮助确定范围中的两个节点是否相邻。例如有以下 HTML 代码:
<p id="p1">Paragraph 1</p><p
id="p2">Paragraph 2</p>
如果事先并不知道标记的结构(比如自动生成的标记),则可以像下面这样创建一个范围:
let p1 = document.getElementById("p1"),
p2 = document.getElementById("p2"),
range = document.createRange();
range.setStartAfter(p1);
range.setStartBefore(p2);
console.log(range.collapsed); // true
在这种情况下,创建的范围是折叠的,因为 p1 后面和 p2 前面没有任何内容。