createRange与Selection API是浏览器原生富文本编辑核心,Range表示文档中连续区域,Selection代表用户可见选区状态;需先获取Selection再操作Range,修改后须removeAllRanges再addRange更新界面。
createrange 与 selection api 是浏览器原生支持的底层接口,用于精确控制富文本编辑器中的光标位置、选区范围和内容操作。它们不依赖第三方库,是实现自定义编辑器(如高亮、插入、格式化、撤销重做等)的核心基础。
理解 Range 与 Selection 的关系
Range 表示文档中一段连续的区域(可以是光标点或文字选区),独立于用户交互;Selection 则代表当前用户“可见”的选区状态,通常包含一个或多个 Range(多选区场景较少见)。编辑器中绝大多数操作需先获取 Selection,再从中提取或创建 Range 进行修改。
关键点:
- Selection 是“当前焦点状态”,可通过
window.getSelection()获取; - Range 是“可操作的数据结构”,用
document.createRange()创建,再通过selectNode()、setStart()/setEnd()等方法定位; - 修改完 Range 后,需调用
selection.removeAllRanges()再addRange(range)才能真正更新界面选区。
常用选区操作的实现方式
以下为富文本编辑器中最典型的四类操作,均基于 createRange + Selection:
-
获取当前选中文本及位置:调用
getSelection().getRangeAt(0)得到 Range,再用range.toString()取文本,range.startContainer和startOffset定位光标起点; -
将光标定位到指定节点末尾:创建 Range →
range.selectNodeContents(node)→range.collapse(false)(false表示折叠到终点)→ 加入 Selection; -
包裹选中内容添加标签(如加粗):获取 Range →
range.extractContents()拿出片段 → 创建<strong></strong>元素 →appendChild()插入片段 →range.insertNode()替换原位置; -
清空选区并聚焦到某处:先
selection.removeAllRanges(),再新建 Range 并collapse(true)(折叠到起点),最后addRange(),必要时调用node.focus()确保可编辑区域获得焦点。
处理边界与兼容性注意事项
真实编辑场景中,选区可能跨文本节点、处于空行、位于 contenteditable=false 元素内,或在 Safari/IE 中行为不一致:
- 避免直接操作
selection.anchorNode,应始终通过getRangeAt(0)获取有效 Range; - 对空选区(光标)执行
extractContents()会返回空 DocumentFragment,需提前判断range.collapsed; - Safari 在某些嵌套结构下可能返回多个 Range,建议统一取第 0 个并限制只处理单 Range 场景;
- IE11 使用
document.selection(已废弃),现代编辑器建议忽略或用 polyfill 封装; - 所有 DOM 修改后,若需保持光标位置稳定,建议记录原始 offset 和 container,在操作后重新构造 Range 定位。
封装一个安全的选区工具函数
实际开发中,可封装一个最小可用的辅助函数,降低出错概率:
function getActiveRange() {
const sel = window.getSelection();
return sel.rangeCount > 0 ? sel.getRangeAt(0).cloneRange() : null;
}
function setCursorAt(node, offset = 0, toEnd = false) {
const range = document.createRange();
range.selectNodeContents(node);
range.collapse(toEnd);
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
这类函数屏蔽了重复校验逻辑,便于在插入图片、切换格式、响应快捷键时复用,也利于后续加入 undo stack 的快照捕获。

















