shallowRef 应用于富文本编辑器实例(如 wangEditor 的 IDomEditor),避免 Vue 深度响应式追踪引发性能问题;大文本内容用 ref<string> 存储,通过 @onChange 同步更新;v-if 隐藏时须调用 destroy() 销毁实例。

shallowRef 在富文本编辑器中不是用来缓存大文本的,而是用来安全持有编辑器实例(Editor 对象),避免 Vue 对其做深度响应式追踪——这恰恰能防止因编辑器内部复杂状态引发的性能问题或意外响应。
大文本内容(比如 <p>...</p><img...> 这类 HTML 字符串)本身是普通字符串,直接用 ref 或 computed + v-model 绑定即可,不需要、也不适合用 shallowRef 存储。
下面说清楚三个关键点:
为什么编辑器实例必须用 shallowRef
- wangEditor 的
IDomEditor实例内部有大量嵌套对象、函数、DOM 引用、事件监听器等。 - 若用
ref(editor),Vue 会尝试递归将其转为响应式,造成:- 内存占用上升
- 初始化变慢
- 可能触发无限循环或警告(如
Maximum recursive updates)
-
shallowRef只让.value本身可响应,内部结构完全跳过响应式系统,正适合这种“只读引用、不追踪内部”的场景。
const editorRef = shallowRef<IDomEditor | null>(null) // ✅ 正确 // 不要写成: // const editorRef = ref<IDomEditor | null>(null) // ❌ 潜在风险
大文本内容该怎么存和更新
HTML 字符串内容应走标准响应式流程:
立即学习“前端免费学习笔记(深入)”;
- 用
ref<string>或computed双向绑定v-model - 编辑器内容变更时,通过
@onChange或@onCreated中监听editor.txt.html()获取最新值 - 提交前直接取
valueHtml.value即可,无需额外“缓存”
const valueHtml = ref<string>('<p>初始内容</p>') // ✅ 文本内容用 ref
// 编辑器创建后,可手动同步一次(可选)
const handleCreated = (editor: IDomEditor) => {
editorRef.value = editor
// 首次回显:若 props 传了初始 HTML,可设 editor.txt.html(props.modelValue)
if (props.modelValue) editor.txt.html(props.modelValue)
}
// 内容变化时更新 ref(推荐用 @onChange,比定时轮询更准)
const handleChange = () => {
valueHtml.value = editorRef.value?.txt.html() || ''
}动态显示/隐藏时注意彻底销毁
如果富文本区域被 v-if 控制显隐(比如表单切换、弹窗打开关闭),每次 v-if="false" 后组件卸载,必须销毁实例:
onBeforeUnmount(() => {
editorRef.value?.destroy() // ✅ 必须调用,释放 DOM 和事件
editorRef.value = null
})不用 v-show,因为 v-show 只切 display,编辑器实例还在内存里跑,容易内存泄漏或状态错乱。
不复杂但容易忽略


















