Selection 与 Range:光标与选区的模型
目标
要操作选区(加粗选中文字、在光标处插图),必须先懂 Selection / Range 这套 API。本节课讲清"光标在哪、选中了哪段",并写一个小工具把它打印出来。
运行环境:浏览器(建议打开 DevTools 控制台跟练)。
运行方式:在 l1 的 index.html 里,把 <script> 换成下面内容,打开后在编辑器里选中一段文字,观察控制台。
<script>
const editor = document.getElementById('editor')
editor.addEventListener('selectionchange', () => {})
document.addEventListener('selectionchange', () => {
const sel = window.getSelection()
if (!sel.rangeCount) return
const range = sel.getRangeAt(0)
console.log('是否折叠(光标无选中):', sel.isCollapsed)
console.log('起点容器:', range.startContainer.nodeName, '偏移:', range.startOffset)
console.log('终点容器:', range.endContainer.nodeName, '偏移:', range.endOffset)
console.log('选中文本:', sel.toString())
})
</script>Range 用"起点容器 + 起点偏移"和"终点容器 + 终点偏移"精确定位一段内容。isCollapsed 为 true 表示只是光标、没选中任何字。
名词解释
Selection(选区):用户当前选中的范围,全局只有一个。通过 window.getSelection() 拿到;getRangeAt(0) 取第一个 Range。
Range(范围):一段连续的文档区间,由起点和终点(各是一个"节点 + 偏移")描述。文本节点里偏移是字符序号;元素节点里偏移是子节点序号。
collapse(折叠):选区收缩成一个光标点(isCollapsed === true),此时起点终点重合。
课后练习
练习:写一个函数 getSelectionText(),返回当前选中的纯文本;若没有选中则返回空串。
答案:
function getSelectionText() {
const sel = window.getSelection()
return sel && sel.rangeCount ? sel.toString() : ''
}总结
Selection / Range 是富文本编辑器所有"精准操作"的坐标系。没有它,你只能在"整篇 HTML"层面字符串替换,一改就乱。它的难点在于"偏移是相对节点的"——同一段文字,可能在文本节点里偏移 5,也可能因为嵌套元素变成"父节点偏移 2"。所以编辑器框架(如 ProseMirror)会把选区也建模进自己的数据模型里,避免直接跟裸 DOM 的偏移纠缠。本课你只要建立直觉:选区 = 起点 + 终点,每个点 = 节点 + 偏移。后面所有"在光标处插入""给选中加粗"都建立在这之上。