背景
在移动端富文本编辑场景中,@人功能需要处理选区操作。在Safari浏览器中,发现当进行以下操作链时:
- 点击「模拟编辑框」,焦点在
step1
的组件,这个时候保存step1
的选区 - 点击「模拟打开@modal并search人员」 模拟输入@modal并 search人员,这个时候不做其他操作
- 点击「模拟确认(确认之后将选区进行替代,这里不进行特殊逻辑)」,这个时候拿到
step1
的选区并且对选区进行读取
操作
在这种情况执行 selectionRef.getRangeAt(0)
控制台会出现IndexSizeError
报错
最小复现代码,见这个链接: codepen.io/yilaikesi/p...
为此还专门在虚拟机上做了一个最小demo ,google上流程执行没有问题,

safari上稳定报错

问题原因
发现Safari的选区机制存在特殊性:
-
选区api差异:
- 执行
selectionRef = window.getSelection()
- 当焦点转移到
<input>
元素后,Safari会自动清空原有选区 , 按道理来说,在保存了选区后,selectionRef 对象应该不变,也就是这个时候的window.getSelection()
应该生成一个getSelection
的快照,但是 在safari
中 上面step2
的选区确认之后,读取step1
的快照并且进行getRangeAt(0)
就会炸掉
- 执行
解决方案
提前读取并保存一份快照,目前的问题是在 step3
中才读取 step1
的选区操作,而在step2
中,执行了选区改变的操作,那么把step3
的读取操作直接放到step1
进行操作并且用range.cloneRange()
操作一下就可以了
具体的解决方案可以参考 codepen.io/yilaikesi/p... 下面被注释掉的地方