必须通过range操作选区,因window.getselection()返回只读快照;需先检查selection.rangecount是否为0,再用deletecontents()+insertnode()安全替换内容。

直接用 window.getSelection() 拿到的是只读快照,不能改内容、不能赋值、不能当字符串直接塞回去——所有“选中后替换失败”“高亮没反应”“光标乱跳”的问题,根源都在跳过了 Range 这一层。
selection.rangeCount === 0 是最常被忽略的起点
很多脚本一上来就调 getSelection().getRangeAt(0),结果报错 IndexSizeError。这不是代码写错了,是根本没选中。
- 页面没聚焦(比如在 iframe 外点击)、
contenteditable="false"容器内、或跨源<iframe></iframe>里,rangeCount都会是 0 - 移动端 Safari 在非
contenteditable元素里长按选中后,rangeCount可能仍为 0 —— 这是策略限制,不是 bug - 检查必须前置:
if (sel.rangeCount === 0) return;,别往后硬写
replace 选中文本必须走 deleteContents() + insertNode()
想把“hello”替换成“world”,不能靠 innerHTML = ... 或拼字符串再塞回去。那样会销毁节点、丢事件、失焦点、破坏嵌套结构。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
-
range.deleteContents()真删 DOM,自动处理跨 Text 节点、嵌套 Element 的情况 - 插入纯文本用
range.insertNode(document.createTextNode('world')),安全且不触发重排 - 插入 HTML 字符串必须先解析:
const div = document.createElement('div'); div.innerHTML = '<em>world</em>'; range.insertNode(div.firstChild); - 别用
surroundContents():它对节点结构极其敏感,稍有不对就抛InvalidStateError
加样式要用 span 包裹,但得防无限嵌套
用 span 给选区加背景色或 class 很常见,但连续操作几次后,<span><span><span>...</span></span></span> 就出来了。
- 先判断选区是否已在外层
span内:range.commonAncestorContainer.closest('span') - 更稳妥的做法是先
extractContents()拿出文档片段,再新建span包一层,最后insertNode() - 如果要取消样式,别用
outerHTML = innerHTML,而是遍历选区内的所有span,用replaceWith(...childNodes)拆出来 - 注意:iOS Safari 中
range.startOffset在输入法上屏瞬间可能不准,视觉对齐建议用range.getBoundingClientRect()
监听 selectionchange 不等于实时响应
document.addEventListener('selectionchange', handler) 听起来很准,但实际漏触发严重。
- 它只在 Selection 对象真正变化时触发(鼠标拖完、Shift+方向键),点击空白、切 tab、软键盘收起都不算
- iframe 内的选区变化,父页完全收不到,必须显式透传:
iframe.contentWindow.document.addEventListener('selectionchange', ...) - 移动端尤其不稳定,建议加防抖 + 主动轮询:
setInterval(() => { if (getSelection().rangeCount > 0) {...} }, 200) - 在
<input>或<textarea></textarea>里,优先用.selectionStart/.selectionEnd,它们可读可写,更可控
真正麻烦的从来不是“怎么加个背景色”,而是跨节点边界时 anchorOffset 和 focusOffset 的语义差异、移动端输入法与 Selection 的时间差、还有 Safari 对非 contenteditable 的硬性封锁——这些细节不手动测一遍,光看 API 文档根本绕不过去。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










