Vue富文本编辑器撤销功能导致光标位置错乱怎么办?
我在用contenteditable做富文本编辑器时,想通过保存历史快照实现撤销功能。但每次undo后光标会跳到开头,而且频繁操作会内存溢出。
现在用Vue维护一个history数组,在input事件里push当前innerHTML。undo方法直接取前一个快照赋值给content,但发现:
<template>
<div
contenteditable
@input="saveState"
v-html="content"
></div>
</template>
<script>
export default {
data() {
return {
content: '<p>初始内容</p>',
history: []
}
},
methods: {
saveState() {
this.history.push(this.content)
this.history = this.history.slice(-20) // 限制长度
},
undo() {
this.history.pop()
this.content = this.history[this.history.length-1]
}
}
}
</script>
这样实现后,撤销确实生效了,但光标总跳到开头,而且快速输入几十次后页面明显卡顿。有没有更好的历史记录管理方案?
光标跳到开头是因为直接修改了content的值,导致浏览器重新渲染整个DOM结构,自然会重置光标。要解决这个问题,需要在undo的时候手动保存和恢复光标位置。可以借助Selection和Range API来处理:
在undo方法里调用这两个辅助方法:
至于性能问题,频繁push完整HTML确实吃内存,建议改成存增量更新。比如只记录每次变化的差异,或者限制history长度在10以内就够了。另外,不要在每个input事件都存快照,可以加个防抖:
这样既解决了光标问题,又优化了性能。记得测试下主流浏览器兼容性,尤其是IE这种老古董可能需要额外打补丁。做富文本编辑器确实挺烦人的,慢慢调吧。