可通过Selection API获取用户选中文本并用<mark>或<span>高亮,需判断selection.isCollapsed避免空选,用range.surroundContents()包裹(限单文本节点)或手动拆分处理跨节点情况,建议添加data属性便于管理与清除。

可以通过 Selection API 获取用户在页面中选中的文本,并动态为其包裹一个带样式的 <mark> 或自定义 <span> 元素来实现高亮标注。
获取当前选中文本内容
使用 window.getSelection() 获取 Selection 对象,再调用其 toString() 方法即可得到纯文本:
const selection = window.getSelection();
if (!selection.isCollapsed) {
const selectedText = selection.toString().trim();
console.log("选中的文本:", selectedText);
}
注意:需判断 selection.isCollapsed === false,避免用户只是点击未拖选时返回空字符串或意外行为。
定位并包装选中范围的 DOM 节点
Selection 对象提供 getRangeAt(0) 获取首个选中范围(Range),再用 range.cloneContents() 或 range.surroundContents() 操作内容:
立即学习“前端免费学习笔记(深入)”;
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
-
range.surroundContents(element)可将选中内容整体包裹进指定元素(如<mark>),但要求选区必须完全位于同一文本节点内,否则会报错; - 更健壮的做法是使用
range.extractContents()+ 创建新节点 +range.insertNode(),支持跨节点选中; - 推荐封装一个安全的高亮函数,先拆分 Range、遍历 Text 节点、逐段替换为带
class="highlight"的<span>。
插入高亮标记并保留原始结构
以下是一个轻量级实现示例(不依赖框架):
function highlightSelection() {
const selection = window.getSelection();
if (selection.isCollapsed || selection.rangeCount === 0) return;
const range = selection.getRangeAt(0).cloneRange();
const span = document.createElement('span');
span.className = 'highlight';
span.style.backgroundColor = '#ffeb3b';
span.style.color = '#333';
try {
range.surroundContents(span); // 简单场景可用
} catch (e) {
// 跨节点时 fallback:手动拆分处理(略去细节,实际项目建议用 rangy 或 selection-api 工具库)
console.warn('选区跨节点,surroundContents 失败,需降级处理');
}
}
绑定到 mouseup 或 contextmenu 事件可触发高亮:
document.addEventListener('mouseup', highlightSelection);
清除或管理已添加的高亮
为便于后续操作(如取消高亮、导出标注),建议给所有高亮 <span> 添加唯一 data 属性,例如 data-highlight-id="h1",并维护一个映射表记录位置与内容。清除时可:
- 通过
document.querySelectorAll('span.highlight')批量移除; - 或用
range.deleteContents()配合保存原始文本还原; - 若需持久化,可将高亮区域序列化为 Range 的 startContainer/startOffset 等信息存入 localStorage。
不复杂但容易忽略:高亮后 Selection 会被破坏,如需保持光标位置,应在操作前用 range.cloneRange() 记录,操作后再用 selection.removeAllRanges() 和 selection.addRange() 恢复。


















