Selection是浏览器级交互状态,代表光标或高亮范围;操作textContent/innerText是DOM值修改,二者不同步;Selection需通过getRangeAt(0)获取Range才能执行deleteContents/insertNode等操作。

选区(Selection)和文本节点操作根本不是一回事
Selection 是浏览器级的用户交互状态,代表光标位置或高亮范围;而直接操作 textContent 或 innerText 是 DOM 树层面的值修改。两者不自动同步:改了文本内容,selection 可能还停在原 offset;反之,用 window.getSelection() 获取到的选区,如果不手动调用 range.deleteContents() 或 range.insertNode(),根本不会影响实际文本。
用 getSelection() + getRangeAt(0) 拿到可操作的范围
用户拖选后,window.getSelection() 返回的是 Selection 对象,它本身不能直接写入或删除——必须先取它的第一个 Range(多数场景只存在一个):
const sel = window.getSelection();
if (sel.rangeCount > 0) {
const range = sel.getRangeAt(0);
// ✅ 现在 range 才是真正可操作的“选区实体”
}
常见错误:直接对 sel 调用 deleteContents() —— 这会报 TypeError: sel.deleteContents is not a function,因为方法在 Range 上,不在 Selection 上。
插入文本时优先用 range.insertNode() 而非 document.execCommand()
document.execCommand() 已废弃,且行为受编辑模式(contenteditable 是否开启、是否在 designMode 下)影响极大;而 range.insertNode() 更可控,尤其适合插入带样式的 HTML 片段:
立即学习“前端免费学习笔记(深入)”;
- 如果插入纯文本,用
range.insertNode(document.createTextNode("xxx")) - 如果要保留格式(如加粗、链接),构造
span或a元素再插入 - 注意:插入后选区会坍缩到新节点末尾,需手动重置光标位置(用
range.collapse(false))
跨浏览器处理光标定位要用 range.setStart() 和 range.setEnd()
想把光标精准放到某段文字末尾?别依赖 element.focus() 后的默认行为——它在 Safari 和 Firefox 下表现不一致。正确做法是手动创建 Range:
const el = document.getElementById("editor");
const range = document.createRange();
range.selectNodeContents(el);
range.collapse(false); // 光标移到末尾
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
关键点:collapse(true) 是移到开头,false 是移到结尾;selectNodeContents() 包含所有子文本节点,比 selectNode() 更可靠,后者在有嵌套标签时容易漏掉文本。
最易被忽略的是:每次操作前必须调用 sel.removeAllRanges(),否则旧选区残留会导致奇怪的叠加行为,尤其在快速连续触发时。



















