HTML选区(Selection)仅描述用户选择范围,不直接修改文本;需通过Range操作DOM节点来实现编辑,且须处理多节点、跨元素及浏览器兼容性问题。

HTML 选区(Selection)本身不直接操作文本内容,它只描述用户在页面中“划了哪一块”,真正修改文本必须通过其关联的 Range 或底层 DOM 节点来完成——这是绝大多数人卡住的第一步。
selection.toString() 只读返回,改不了内容
很多人以为 selection.toString() 拿到文本后替换再塞回去就能编辑,其实不行:toString() 是纯字符串快照,和 DOM 无绑定。改它等于改了个假副本。
- 正确做法是先用
selection.getRangeAt(0)获取Range,再调用range.deleteContents()清除原选区,最后用range.insertNode()或range.insertNode(document.createTextNode('新文本'))插入 - 如果选区跨多个文本节点(比如横跨两个
<span></span>),range.toString()仍能拼出连续文本,但直接range.deleteContents()会破坏节点结构,需手动合并或重写逻辑 - 注意:IE 低版本用
selection.createRange()返回的是专有TextRange对象,API 完全不同,现代项目建议用getRangeAt(0)+ 特性检测兜底
document.execCommand() 已废弃,但仍有实用场景
document.execCommand() 能快速加粗、插入链接等,但它依赖当前 selection 状态,且在现代浏览器中已被标记为废弃(MDN 明确标注)。不过它还没被移除,某些管理后台或富文本轻量需求里仍可短期用。
将 Markdown 文章转换为微信公众号兼容的纯 HTML 格式。当用户要求"转成微信格式"、"生成公众号文章 HTML"、"排版到微信草稿箱"、"微信粘贴格式"时触发。输出带内联样式的纯 HTML,微信编辑器可直接渲染,无需额外适配。支持标题、段落、列表、粗体、行内代码、表格、引用块、代码块、配图的完整转换。
- 它只对可编辑区域(
contenteditable="true"或designMode = "on")生效;普通页面调用无效,也不报错,容易误判 -
execCommand('insertText', false, 'xxx')会把选区替换成纯文本,但会丢失格式;而'insertHTML'则可能触发 XSS(若未转义输入) - 替代方案是手动操作
Range+DocumentFragment,控制力更强,但代码量翻倍——别为了“标准”硬换,要看是否真需要细粒度控制
监听 selectionchange 事件要注意触发时机
document.addEventListener('selectionchange', handler) 看似简单,但实际触发条件比想象中苛刻:
立即学习“前端免费学习笔记(深入)”;
- 仅当
Selection对象本身变化时才触发(比如鼠标拖完、键盘 Shift+方向键),点击空白处、聚焦 input 框、甚至切换 tab 都不会触发 - 在 iframe 内操作时,事件只在对应 iframe 的
document上触发,父页监听不到,需显式透传 - 移动端 Safari 对该事件支持不稳定,尤其在软键盘弹起/收起过程中常丢失一次触发,建议加防抖 + 主动轮询
getSelection().rangeCount作为 fallback
最常被忽略的一点:选区可能为空(rangeCount === 0),也可能包含多个 range(比如按 Ctrl 多选),但绝大多数文本操作逻辑只处理第一个 range,没做防御就直接 getRangeAt(0) 会报错。别假设用户一定单选、一定有内容。


















