WangEditor 富文本编辑器实战踩坑与优化技巧分享
又踩坑了,WangEditor 上传图片后光标乱跑
上周在项目里集成 WangEditor,本来以为就是个富文本编辑器,复制粘贴图片、拖拽上传,搞定收工。结果测试一跑,发现上传完一张图,光标直接跳到文章开头去了——用户刚写完一段文字,点上传,图是上去了,但光标没了,得手动再点回编辑区域继续写。这体验太差了,我当场就懵了。
一开始我以为是自己用法不对,翻了下官方文档,发现人家 demo 里上传完光标位置是正常的。那问题肯定出在我这儿。折腾了半天,试了各种方法:先是在 onSuccess 回调里手动 focus,结果没用;又去查编辑器实例有没有恢复光标的方法,文档里提到 restoreSelection,但调用时报错说 selection 不存在;甚至怀疑是不是 Vue 的响应式更新导致 DOM 重绘,把 selection 干掉了……
后来我冷静下来,打开浏览器 devtools,打了个断点,在上传前记录一下当前的 selection 范围:
const selection = window.getSelection();
const range = selection.getRangeAt(0);
console.log('上传前 range', range);
上传完成后,再看 selection,果然是空的。说明在图片插入过程中,DOM 结构被替换了,或者编辑器内部重新渲染了内容,导致原生 selection 丢失。WangEditor 内部其实是有自己的 selection 管理机制的,但默认情况下,上传组件并不会帮你保存和恢复光标位置。
这里我踩了个坑:以为只要调用 editor.txt.insert() 插入内容,光标就会自动跟过去。实际上,如果你是在异步回调里插入(比如上传成功后),此时用户可能已经做了其他操作,或者编辑器内部状态已经变化,原生 selection 早就失效了。
核心代码就这几行
解决思路其实很简单:在触发上传前,先保存当前的编辑器选区(不是原生 selection,而是 WangEditor 提供的 API);上传成功后,先恢复选区,再插入图片。这样光标就能停留在正确位置了。
WangEditor 从 v5 开始提供了 saveSelection 和 restoreSelection 方法,但很多人不知道要在什么时候用。我试了下,必须在用户交互(比如点击上传按钮)的同步上下文中调用 saveSelection,否则保存的可能是无效状态。
最终代码长这样:
// 初始化编辑器
const editor = new wangEditor('#editor');
editor.config.uploadImgServer = 'https://jztheme.com/api/upload-image';
editor.config.uploadImgShowBase64 = false;
// 关键:自定义上传逻辑
editor.config.customUploadImg = function (resultFiles, insertImgFn) {
// 1. 上传前保存选区
const savedSelection = editor.selection.saveSelection();
resultFiles.forEach(file => {
const formData = new FormData();
formData.append('image', file);
fetch('https://jztheme.com/api/upload-image', {
method: 'POST',
body: formData
})
.then(res => res.json())
.then(data => {
if (data.url) {
// 2. 恢复选区(必须在插入前)
editor.selection.restoreSelection(savedSelection);
// 3. 插入图片
insertImgFn(data.url);
}
})
.catch(err => {
console.error('上传失败', err);
// 如果失败,也可以选择恢复选区让用户继续编辑
editor.selection.restoreSelection(savedSelection);
});
};
};
editor.create();
注意几个细节:
saveSelection必须在用户触发上传的同步流程里调用,比如点击“上传图片”按钮时,或者监听文件 input 的 change 事件时。不能等到异步回调里才保存,那时候 selection 已经丢了。restoreSelection要在insertImgFn之前调用,否则插入内容时没有有效选区,光标位置还是不对。- 如果上传失败,最好也恢复一下选区,不然用户会发现编辑器“卡住”了,点哪都没反应。
这个方案亲测有效。我本地测试了多次,不管是单张还是多张图片,上传后光标都稳稳停在插入位置后面,可以继续打字。
为什么官方 demo 没这个问题?
后来我去扒了 WangEditor 的官方 demo 源码,发现他们用的是 base64 内联上传(uploadImgShowBase64: true),这种模式下图片是同步插入的,不会触发异步网络请求,所以 selection 不会丢失。但实际项目中没人用 base64,图片太大,还得转存到服务器,所以必须走异步。
也就是说,这个问题只会在你使用 customUploadImg 或者配置了 uploadImgServer 且走真实网络请求时才会出现。很多教程直接抄官方 demo,没考虑异步场景,所以坑就埋下了。
还有个小瑕疵
改完之后基本没问题了,但有一个小细节:如果用户在上传过程中快速点击编辑器其他地方,可能会导致 savedSelection 失效。不过这种情况比较极端,而且即使失效,最多就是光标回到开头,不至于崩溃。考虑到开发成本和实际使用频率,我就没再处理——毕竟用户正常操作不会一边上传一边乱点。
如果你项目要求极高,可以加个 loading 状态禁止交互,或者用更复杂的 selection 快照机制(比如监听 DOM 变化),但我觉得没必要。简单方案够用就行。
踩坑提醒:这三点一定注意
总结一下,用 WangEditor 做异步上传时,务必注意:
- 保存选区要在用户交互的同步上下文中,比如 click 或 change 事件处理函数里,不能在 setTimeout 或 fetch 回调里。
- 恢复选区必须在插入内容之前,顺序不能反。
- 别信默认配置能 cover 所有场景,特别是涉及异步操作的,WangEditor 的默认上传逻辑对光标位置没做保护。
以上是我踩坑后的总结,如果你有更好的方案欢迎评论区交流。比如有没有人试过用 MutationObserver 监听 DOM 变化来自动恢复光标?或者 WangEditor 新版本有没有内置解决这个问题?反正我现在这个方案能跑,先上线再说 😅

暂无评论