无需登录 数据私有 本地保存

Selection API 浏览器 - 获取选中文本与位置信息

6
0
0
0

Selection API 浏览器 - 获取选中文本与位置信息

实时监测文本选择,获取选中内容、坐标、节点信息等详细数据

文本选择区域

📖 浏览器 Selection API 详解

Selection API 是现代浏览器提供的一套强大接口,允许开发者获取和操作用户在网页上选中的文本。 通过 window.getSelection() 方法,你可以轻松获取用户当前选中的内容、判断选择范围、甚至通过编程方式设置选区。

这个 API 在富文本编辑器、文本标注工具、划词翻译、在线笔记等场景中有着广泛的应用。 它不仅仅能获取纯文本,还能获取选中内容所在的 DOM 节点信息,以及精确的像素坐标位置。

🔍 核心概念

每个 Selection 对象都包含以下几个关键属性:

  • anchorNode / anchorOffset — 选择起始点的 DOM 节点和偏移量
  • focusNode / focusOffset — 选择结束点的 DOM 节点和偏移量
  • isCollapsed — 判断选择是否折叠(即光标位置,无实际选中内容)
  • rangeCount — 当前选区包含的 Range 对象数量
  • type — 选区类型:None、Caret 或 Range

📐 位置信息获取

通过 range.getBoundingClientRect() 可以获取选中文本相对于浏览器视口的精确位置, 返回包含 topleftrightbottomwidthheight 的 DOMRect 对象。 如果选中文本跨越多行,range.getClientRects() 会返回每一行对应的矩形列表。

💻 代码示例

// 获取当前选中的文本
const selection = window.getSelection();
if (!selection.isCollapsed) {
  const text = selection.toString();
  const range = selection.getRangeAt(0);
  const rect = range.getBoundingClientRect();
  console.log('选中文本:', text);
  console.log('位置:', rect.top, rect.left);
  console.log('宽度:', rect.width, '高度:', rect.height);
}

👆 在上方文本区域中拖拽选择任意文本,右侧面板将实时展示详细的 Selection API 数据。试试跨段落选择,观察位置信息的变化吧!

选中文本内容
尚未选择文本
等待选择
基本属性
等待文本选择...
视口坐标 (getBoundingClientRect)
top:
left:
right:
bottom:
width:
height:
页面坐标 (视口坐标 + 滚动偏移)
pageTop:
pageLeft:
Anchor / Focus 节点信息
anchorNode anchorOffset
focusNode focusOffset
选中内容的 HTML (cloneContents)

常见问题

Selection API 是浏览器原生提供的 JavaScript 接口,用于获取和操作用户在网页上选中的文本。通过 window.getSelection() 即可获取 Selection 对象。它广泛应用于富文本编辑器(如设置加粗、斜体)、划词翻译工具(获取选中词并翻译)、在线标注/批注系统(高亮选中文本并添加注释)、以及文本复制增强等场景。相比传统的 input/textarea 选择,Selection API 可以处理任意 DOM 元素中的文本选择。

anchorNode 是用户开始选择时鼠标按下的位置所在的 DOM 节点,focusNode 是用户释放鼠标时(选择结束)所在的 DOM 节点。在从左到右的正常拖拽选择中,anchor 在左侧、focus 在右侧;但如果用户从右向左拖拽(反向选择),anchor 会在右侧、focus 在左侧。anchorOffsetfocusOffset 分别表示在对应节点中的字符偏移量。理解这两个概念对于处理方向感知的文本选择非常重要。

range.getBoundingClientRect() 返回一个最小的包围矩形(DOMRect),包含选中文本的整体边界。当选中文本在同一行时,它精确描述该行文本的矩形区域。

range.getClientRects() 返回一个 DOMRectList,当选中文本跨越多行时,每一行都会生成一个独立的矩形。例如选中3行文本,getClientRects()会返回3个DOMRect对象。这在需要逐行高亮精确绘制选择背景时非常有用。两种方法返回的坐标都是相对于浏览器视口的。

使用 selection.isCollapsed 属性。当该属性为 true 时,表示选择是"折叠"的——即光标处于某个位置但没有实际选中任何文本(类似于在文本中间点击了一下)。当它为 false 时,表示用户确实选中了一段文本。另外还可以检查 selection.toString().length > 0selection.type === 'Range' 来判断是否有实际选中内容。

使用 range.cloneContents() 方法可以获取选中内容的DOM片段副本(不会影响原始DOM)。然后将其放入一个临时容器中读取 innerHTML:

const fragment = range.cloneContents();
const tempDiv = document.createElement('div');
tempDiv.appendChild(fragment);
const htmlString = tempDiv.innerHTML;

这样就能获得选中文本的 HTML 表示,保留了加粗、斜体、链接等格式信息。注意 cloneContents() 会自动补全不完整的标签。

Selection API 是所有现代浏览器都完全支持的标准 API,包括 Chrome、Firefox、Safari、Edge 以及移动端的 iOS Safari 和 Android Chrome。它属于 DOM 规范的一部分(W3C Selection API),可以放心在生产环境中使用。需要注意的是,IE 8 及以下版本使用不同的实现方式,但这些浏览器目前已基本淘汰。

可以通过以下步骤编程设置选区:

1. 创建一个 Range 对象:const range = document.createRange();
2. 设置范围的起止位置:range.setStart(startNode, startOffset);range.setEnd(endNode, endOffset);
3. 获取 Selection 对象并应用:const sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range);

如果要选中整个元素的内容,可以使用 range.selectNodeContents(element) 简化操作。这也是本工具"全选"按钮的实现原理。

这是因为点击按钮时,浏览器的默认行为会将焦点转移到按钮上,导致之前的文本选区被清除。解决方案是在按钮的 mousedown 事件中调用 e.preventDefault(),阻止焦点转移。或者,在 selectionchange 事件触发时将选区数据缓存到变量中,按钮点击时使用缓存的数据而非实时获取。本工具采用了这两种策略的结合,确保复制按钮不会干扰文本选择。