今天学习一个新的API---Range&Selection

5 阅读3分钟

一般做鼠标框选文本时会用到这两个API

文章摘选自:segmentfault.com/a/119000004…

Range

Range 接口表示一个包含节点与文本节点的一部分的文档片段。

可以使用 Document.createRange 方法创建 Range。也可以用 Selection 对象的 getRangeAt() 方法或者 Document 对象的 caretRangeFromPoint() 方法获取 Range 对象。

还可以用 Range() 构造函数。

Range的属性

startaaContainer:起始节点。startOffset:起始节点偏移量。endContainer:结束节点。endOffset:结束节点偏移量。collapsed:范围的开始和结束是否为同一点。commonAncestorContainer:返回完整包含 startContainer 和 endContainer 的最深一级的节点
(返回包含全部所选范围的最近父节点)。

Range的方法

  1. cloneContents()

cloneContents():复制范围内容,并将复制的内容作为 DocumentFragment 返回。

const range = document.createRange();
range.selectNode(document.getElementsByTagName("div").item(0));
const documentFragment = range.cloneContents();
document.body.appendChild(documentFragment);

2. cloneRange()

**cloneRange():**创建一个具有相同起点/终点的新范围, 非引用,可以随意改变,不会影响另一方。

const range = document.createRange();
range.selectNode(document.getElementsByTagName("div").item(0));
const clone = range.cloneRange();

3.collapse()

**collapse(toStart):如果 toStart=true 则设置 end=start,否则设置 start=end,从而折叠范围。
**

const range = document.createRange();
const referenceNode = document.getElementsByTagName("div").item(0);
range.selectNode(referenceNode);
range.collapse(true);

4.compareBoundaryPoints()

**compareBoundaryPoints(how, sourceRange):两个范围边界点进行比较,返回一个数字 -1、0、1。
**

const range = document.createRange();
range.selectNode(document.querySelector("div"));
const sourceRange = document.createRange();
sourceRange.selectNode(document.getElementsByTagName("div")[1]);
const compare = range.compareBoundaryPoints(Range.START_TO_END, sourceRange);

5.comparePoint()

**comparePoint(referenceNode, offset):返回-1、0、1具体取决于 是 referenceNode 在 之前、相同还是之后。
**

const range = document.createRange();
range.selectNode(document.getElementsByTagName("div").item(0));
const returnValue = range.comparePoint(document.getElementsByTagName("p").item(0), 1);

6. createContextualFragment()

**comparePoint(referenceNode, offset):返回-1、0、1具体取决于 是 referenceNode 在 之前、相同还是之后。
**

const range = document.createRange();
range.selectNode(document.getElementsByTagName("div").item(0));
const returnValue = range.comparePoint(document.getElementsByTagName("p").item(0), 1);

7. deleteContents()

**deleteContents():删除框选的内容。
**

const range = document.createRange();
range.selectNode(document.getElementsByTagName("div").item(0));
range.deleteContents();

8.extractContents()

**extractContents():从文档中删除范围内容,并将删除的内容作为 DocumentFragment 返回。
**

const range = document.createRange();
range.selectNode(document.getElementsByTagName("div").item(0));
const documentFragment = range.extractContents();
document.body.appendChild(documentFragment);
9. getBoundingClientRect()

getBoundingClientRect():和 dom 一样,返回 DOMRect 对象。

const range = document.createRange();
range.setStartBefore(document.getElementsByTagName("em").item(0));
range.setEndAfter(document.getElementsByTagName("em").item(1));
const clientRect = range.getBoundingClientRect();
const highlight = document.getElementById("highlight");
highlight.style.left = `${clientRect.x}px`;
highlight.style.top = `${clientRect.y}px`;
highlight.style.width = `${clientRect.width}px`;
highlight.style.height = `${clientRect.height}px`;
10. getClientRects()

getClientRects():返回可迭代的对象序列 DOMRect

const range = document.createRange();
range.selectNode(document.querySelector("div"));
const rectList = range.getClientRects();
const output = document.querySelector("#output");
for (const rect of rectList) {
  output.textContent = `${output.textContent}\n${rect.width}:${rect.height}`;
}
11. insertNode()

insertNode(node):在范围的起始处将 node 插入文档。

const range = document.createRange();
const newNode = document.createElement("p");
newNode.appendChild(document.createTextNode("New Node Inserted Here"));
range.selectNode(document.getElementsByTagName("div").item(0));
range.insertNode(newNode);
12. intersectsNode()

intersectsNode(referenceNode):判断与给定的 node 是否相交。

const range = document.createRange();
range.selectNode(document.getElementsByTagName("div").item(0));
const intersectingNode = range.intersectsNode(
  document.getElementsByTagName("p").item(0),
);
13. selectNode()

selectNode(node):设置范围以选择整个 node

const range = document.createRange();
const referenceNode = document.querySelector("div");
range.selectNodeContents(referenceNode);
14. selectNodeContents()

selectNodeContents(node):设置范围以选择整个 node 的内容。

const range = document.createRange();
const referenceNode = document.querySelector("div");
range.selectNodeContents(referenceNode);
15. setStart()

setStart(startNode, startOffset):设置起点。

const element = document.getElementById("content");
const textNode = element.childNodes[0];
const range = document.createRange();
range.setStart(textNode, 0); // Start at first character
range.setEnd(textNode, 5); // End at fifth character
document.getElementById("log").textContent = range;
16. setEnd()

setEnd(endNode, endOffset):设置终点。

const range = document.createRange();
const endNode = document.getElementsByTagName("p").item(3);
const endOffset = endNode.childNodes.length;
range.setEnd(endNode, endOffset);
17. setStartBefore()

setStartBefore(node):将起点设置在 node 前面。

const range = document.createRange();
const referenceNode = document.getElementsByTagName("div").item(0);
range.setStartBefore(referenceNode);
18. setStartAfter()

setStartAfter(node):将起点设置在 node 后面。

const range = document.createRange();
const referenceNode = document.getElementsByTagName("div").item(0);
range.setStartAfter(referenceNode);
19. setEndBefore()

setEndBefore(node):将终点设置为 node 前面。

const range = document.createRange();
const referenceNode = document.getElementsByTagName("div").item(0);
range.setEndBefore(referenceNode);
20. setEndAfter()

setEndAfter(node):将终点设置为 node 后面。

const range = document.createRange();
const referenceNode = document.getElementsByTagName("div").item(0);
range.setEndAfter(referenceNode);
21. surroundContents()

surroundContents(node):使用 node 将所选范围内容包裹起来。

const range = document.createRange();
const newParent = document.createElement("h1");
range.selectNode(document.querySelector(".header-text"));
range.surroundContents(newParent);

创建 Range 的方法

1. Document.createRange
const range = document.createRange();
2. Selection 的 getRangeAt() 方法
const range = window.getSelection().getRangeAt(0)
3. caretRangeFromPoint() 方法
if (document.caretRangeFromPoint) {
    range = document.caretRangeFromPoint(e.clientX, e.clientY);
}
4. Range() 构造函数
const range = new Range()