Vue3 script setup中如何将TipTap绑定到父组件v-model
报错根因
@tiptap/vue-3 的 useEditor 组合式API返回值是shallowRef类型的编辑器实例引用,你在onUpdate回调中直接调用editor.getHTML()时,操作的是外层ref包装对象,该对象本身不存在getHTML方法,因此抛出类型错误。
除此之外你当前的实现缺少父组件传值变更的同步逻辑,外部修改v-model绑定值时编辑器内容不会同步更新。
修正方案
子组件完整实现
所有编辑器实例的方法调用都需要通过.value取到真实实例后操作,同时增加watch监听props变化,做双向同步,注意避免更新循环:
<template> <div id="cms-custom-editor" class="cms-custom-editor"> <editor-content :editor="editor" /> </div> </template> <script setup> import { useEditor, EditorContent } from '@tiptap/vue-3' import StarterKit from '@tiptap/starter-kit' import { watch } from 'vue' const props = defineProps({ modelValue: { type: String, default: '' } }) const emit = defineEmits(['update:modelValue']) const editor = useEditor({ extensions: [StarterKit], content: props.modelValue, onUpdate: () => { // 通过.value访问真实实例,加可选链规避初始化阶段的空值错误 emit('update:modelValue', editor.value?.getHTML() ?? '') } }) // 同步父组件传入的内容变更 watch(() => props.modelValue, (newContent) => { if (!editor.value) return // 内容一致时跳过更新,避免循环触发 if (editor.value.getHTML() === newContent) return // 第二个参数传false,禁止本次setContent触发update事件,切断更新循环 editor.value.commands.setContent(newContent, false) }) </script>
父组件写法优化
Vue3默认v-model的绑定属性就是modelValue,不需要显式写参数,直接用v-model即可:
<template> <cms-custom-editor v-model="state.content"/> <p>{{state.content}}</p> </template> <script setup> import CmsCustomEditor from '../../components/backend/cms-custom-editor.vue' import { reactive } from "vue"; const state = reactive({ content: '<p>A Vue.js wrapper component for tiptap to use <code>v-model</code>.</p>', }) </script>
关键注意点
useEditor返回的是shallowRef,不要直接解构,始终通过.value访问真实编辑器实例- 编辑器初始化是异步过程,组件挂载初期
editor.value可能为null,调用实例方法时建议加可选链做空值保护 - 外部内容同步到编辑器时,必须给
setContent传第二个参数false,否则会触发编辑器的update事件,造成「更新内容→emit→父组件值变更→watch触发→再次setContent」的死循环
内容的提问来源于stack exchange,提问作者Artur Müller Romanov
相关产品推荐
相关产品推荐

