当前位置: 首页 > news >正文

JavaScript Selection API详解

JavaScript Selection API 是用于操作和获取用户在网页中选中的文本内容的接口。它提供了一系列方法和属性,使开发者能够获取、修改和监控用户在页面上的文本选择,可以用于实现富文本编辑器、文本高亮、自定义选择逻辑等功能。以下是 Selection API 的详细解析:


1. 核心概念

Selection API 主要涉及以下几个核心对象和概念:

  • Selection 对象:表示用户在页面中选中的文本范围。可以通过 window.getSelection() 获取当前的 Selection 对象。
  • Range 对象:表示文档中的一个连续范围,可以包含部分或全部节点。Selection 对象可以包含一个或多个 Range 对象。
  • 锚点(Anchor)和焦点(Focus):Selection 对象的起始点称为锚点,结束点称为焦点。如果用户从左向右选择文本,锚点在左,焦点在右;反之亦然。

2. Selection 对象的属性

属性描述
anchorNode返回 Selection 的锚点所在的节点。
anchorOffset返回 Selection 的锚点在 anchorNode 中的偏移量。
focusNode返回 Selection 的焦点所在的节点。
focusOffset返回 Selection 的焦点在 focusNode 中的偏移量。
isCollapsed如果 Selection 的起始点和结束点相同,返回 true,表示没有选中任何文本。
rangeCount返回 Selection 中包含的 Range 对象的数量。
type返回 Selection 的类型,如 "None""Caret""Range"

3. Selection 对象的方法

方法描述
getRangeAt(index)返回 Selection 中指定索引的 Range 对象。
addRange(range)向 Selection 中添加一个 Range 对象。
removeRange(range)从 Selection 中移除一个 Range 对象。
removeAllRanges()移除 Selection 中的所有 Range 对象。
collapse(node, offset)将 Selection 的起始点和结束点移动到指定的节点和偏移量。
extend(node, offset)将 Selection 的焦点移动到指定的节点和偏移量。
selectAllChildren(node)将 Selection 的范围扩展到包含指定节点的所有子节点。
deleteFromDocument()从文档中删除 Selection 的内容。
toString()返回 Selection 的文本内容。

4. Selection 对象使用示例

4.1. 示例:获取选中的文本

const selection = window.getSelection();
if (!selection.isCollapsed) {const selectedText = selection.toString();console.log("选中的文本:", selectedText);
}

4.2. 示例:修改选中的文本

const selection = window.getSelection();
if (!selection.isCollapsed) {const range = selection.getRangeAt(0);const newTextNode = document.createTextNode("新文本");range.deleteContents(); // 删除选中的内容range.insertNode(newTextNode); // 插入新文本
}

4.3. 监控 Selection 的变化

可以通过监听 selectionchange 事件来监控 Selection 的变化:

document.addEventListener("selectionchange", () => {const selection = window.getSelection();console.log("Selection 变化:", selection.toString());
});

5. Range 对象的属性

属性描述
startContainer返回 Range 的起始节点。
startOffset返回 Range 的起始节点中的偏移量。
endContainer返回 Range 的结束节点。
endOffset返回 Range 的结束节点中的偏移量。
collapsed如果 Range 的起始点和结束点相同,返回 true
commonAncestorContainer返回包含 startContainerendContainer 的最深层的共同祖先节点。

6. Range 对象的方法

6.1 设置 Range 的范围

方法描述
setStart(node, offset)设置 Range 的起始点为指定节点和偏移量。
setEnd(node, offset)设置 Range 的结束点为指定节点和偏移量。
setStartBefore(node)将 Range 的起始点设置为指定节点之前。
setStartAfter(node)将 Range 的起始点设置为指定节点之后。
setEndBefore(node)将 Range 的结束点设置为指定节点之前。
setEndAfter(node)将 Range 的结束点设置为指定节点之后。

示例:

const range = new Range();
const element = document.getElementById("example");
range.setStart(element, 0); // 将起始点设置为 element 的第一个子节点之前
range.setEnd(element, 1);   // 将结束点设置为 element 的第一个子节点之后

6.2 选择节点

方法描述
selectNode(node)将 Range 设置为包含指定节点及其所有子节点。
selectNodeContents(node)将 Range 设置为包含指定节点的所有子节点。

示例:

const range = new Range();
const element = document.getElementById("example");
range.selectNode(element); // 选择整个 element 节点
// 或
range.selectNodeContents(element); // 选择 element 的所有子节点

6.3 操作 Range 的内容

方法描述
deleteContents()删除 Range 所包含的内容。
extractContents()从文档中提取 Range 的内容,并返回一个 DocumentFragment
cloneContents()克隆 Range 的内容,并返回一个 DocumentFragment
insertNode(node)在 Range 的起始点插入一个节点。
surroundContents(newParent)将 Range 的内容包裹在一个新的父节点中。

示例:

const range = new Range();
const element = document.getElementById("example");
range.selectNodeContents(element);
range.deleteContents(); // 删除 element 的所有子节点
// 或
const fragment = range.extractContents(); // 提取内容
// 或
const newNode = document.createElement("span");
range.insertNode(newNode); // 在 Range 的起始点插入新节点

6.4 比较 Range 的位置

方法描述
compareBoundaryPoints(type, otherRange)比较两个 Range 的边界点。type 可以是:Range.START_TO_STARTRange.END_TO_ENDRange.START_TO_ENDRange.END_TO_START
isPointInRange(node, offset)检查指定的节点和偏移量是否在 Range 内。
intersectsNode(node)检查 Range 是否与指定节点相交。

示例:

const range1 = new Range();
const range2 = new Range();
const result = range1.compareBoundaryPoints(Range.START_TO_START, range2);
console.log(result); // -1, 0, 或 1

6.5 克隆和拓展 Range

方法描述
cloneRange()克隆一个 Range 对象。
collapse(toStart)将 Range 的结束点移动到起始点。toStarttrue 时,Range 将折叠到起始点;为 false 时,折叠到结束点。
detach()释放 Range 对象,使其不再引用文档。

示例:

const range = new Range();
range.setStart(element, 0);
range.setEnd(element, 1);
const clonedRange = range.cloneRange(); // 克隆 Range
range.collapse(true); // 折叠到起始点

7. 综合示例:使用JavaScript Selection API修改文档内容

以下示例展示两行文本和一个加粗按钮,任意选择部分文本,按下加粗按钮,选中的文本将被一个class属性为new-strongstrong结点包围,且原有的html标签结构不会被破坏。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>加粗选中文本</title><style>button {margin: 10px;padding: 5px 10px;}.new-strong {color: green;}</style>
</head>
<body><div>第一块<span>234<span>567</span></span></div><div>第二块</div><button id="boldButton">加粗</button><script>document.getElementById("boldButton").addEventListener("click", function() {const selection = window.getSelection();if (selection.rangeCount > 0) {const range = selection.getRangeAt(0);if (!range.collapsed) {// 处理选中的文本surroundSelectedTextWithNewNode(range, "strong", "new-strong");// 清除选中状态selection.removeAllRanges();}}});function surroundSelectedTextWithNewNode(range, tagName, className) {// 获取选中的文本节点const textNodes = getTextNodesInRange(range);// 对每个文本节点进行处理textNodes.forEach(node => {const parent = node.parentNode;const text = node.nodeValue;const startOffset = node === range.startContainer ? range.startOffset : 0;const endOffset = node === range.endContainer ? range.endOffset : text.length;			const newNode = document.createElement(tagName);newNode.classList.add(className);if (startOffset > 0 || endOffset < text.length) {// 截取被选中的部分const beforeText = text.substring(0, startOffset);const selectedText = text.substring(startOffset, endOffset);const afterText = text.substring(endOffset);// 创建新的文本节点const beforeNode = document.createTextNode(beforeText);const afterNode = document.createTextNode(afterText);newNode.appendChild(document.createTextNode(selectedText));// 替换原文本节点parent.insertBefore(beforeNode, node);parent.insertBefore(newNode, node);parent.insertBefore(afterNode, node);parent.removeChild(node);} else {// 整个文本节点被选中newNode.appendChild(node.cloneNode(true));parent.insertBefore(newNode, node);parent.removeChild(node);}// 控制台输出当前结点修改后的html以观察效果if(parent !== document.body){console.log(parent.outerHTML);}});}function getTextNodesInRange(range) {const textNodes = [];const startNode = range.startContainer;const endNode = range.endContainer;const startOffset = range.startOffset;const endOffset = range.endOffset;// 从 startNode 开始遍历,直到 endNodelet currentNode = startNode;while (currentNode && currentNode !== endNode) {if (currentNode.nodeType === Node.TEXT_NODE) {textNodes.push(currentNode);}currentNode = getNextNode(currentNode);}// 添加 endNode(如果是文本节点)if (endNode.nodeType === Node.TEXT_NODE) {textNodes.push(endNode);}return textNodes;}function getNextNode(node) {if (node.firstChild) {return node.firstChild;}while (node) {if (node.nextSibling) {return node.nextSibling;}node = node.parentNode;}return null;}</script>
</body>
</html>

在浏览器中运行上面的网页,选择绿色部分文字(原本是无格式的),然后点击“加粗”按钮,无格式文本就变成了加粗绿色格式了:
在这里插入图片描述
原始的html结构:

<div>第一块<span>234<span>567</span></span></div>
<div>第二块</div>

在控制台中的输出如下:
在这里插入图片描述
可以看到没有破坏原始的html结构,文本格式化标签均为纯文本结点的直接父结点。


8. 注意事项

  • 浏览器兼容性:Selection API 在现代浏览器中支持良好,但在旧版本的浏览器中可能存在兼容性问题。
http://www.dtcms.com/a/583059.html

相关文章:

  • 深圳专业AI优化实践案例:潮视新创引领行业变革
  • 江苏省住房和城乡建设网站东莞网站建设硅胶
  • 做驾校题目用什么网站好网站开发ppt方案模板
  • 西安搬家公司招聘网站优化网站建设公司
  • 1BBE-2ECD流水灯芯片20路 led灯带跑马灯驱动芯片 追尾流星雨灯IC
  • 做网站接私活流程网站建设预算项目
  • 淮南网站建设全包wordpress 免费中文模板下载地址
  • C# EventWaitHandle
  • 如何运营网站制作企业官网哪家好
  • 十堰哪家网站制作公司技术好企点登录
  • 七彩喜智慧康养:用科技的温度,重新定义“老有所依”
  • Tomcat8版本升级教程
  • 2026商业航天展,解锁商业航天产业全链条创新图景
  • wordpress演示站功能基于WordPress开发
  • 解决蛋白质构象异质性的原子级建模挑战!David Baker团队PLACER框架解析
  • 兴平住房和城乡建设局门户网站wordpress 表单校验
  • wordpress发布文章到指定页面网站怎么关键字优化
  • 做农资的网站公司名字大全免费测吉凶
  • 岳阳市交通建设投资公司门户网站wordpress主题汉化中文
  • 安防公司做网站图片湖南省郴州市十大旅游景点排行榜
  • 博物馆门户网站建设目标seo如何快速出排名
  • 影视网站的设计与实现网络服务提供者不履行法律行政法规规定的
  • 官方网站做背景墙厂家网站的开发方式
  • onethink做的企业网站在县城做商城网站
  • 【智能体-DeepMiner】利用滑动窗口 提高多轮交互能力
  • [尚庭公寓P159-169][结束][第7天]
  • 做网站用哪个编程语言wordpress多用户商城
  • 门户网站框架下载wordpress 果蔬论坛
  • C++并查集
  • Linux开发:readlink命令读取软连接指向的文件