如何向TipTap中的自定义Vue扩展传递挂载后生成的响应式数据?
向TipTap自定义Vue组件传递响应式数据失效问题解决
我在TipTap编辑器中渲染自定义Vue组件时,默认属性能正常传递,但使用编辑器挂载后创建的响应式值时,数据变成undefined,无法生效。
相关代码文件
tiptap-node-extension.js
import {Node, mergeAttributes} from '@tiptap/core' import {VueNodeViewRenderer} from '@tiptap/vue-3' import Component from '@/views/components/vue-component.vue' export default Node.create({ parseHTML() { return [{ tag: 'vue-component' }] }, renderHTML({ HTMLAttributes }) { return ['vue-component', mergeAttributes(HTMLAttributes)] }, addNodeView() { return VueNodeViewRenderer(Component) }, })
编辑器组件的script setup部分
<script setup> import {useEditor, EditorContent, BubbleMenu} from '@tiptap/vue-3' import StarterKit from '@tiptap/starter-kit' import {Underline} from "@tiptap/extension-underline"; import {TextAlign} from "@tiptap/extension-text-align"; import {Link} from "@tiptap/extension-link"; import VueComponent from '@/js/tiptap-node-extension.js' const editor = useEditor({ extensions: [ StarterKit, TextAlign.configure({ types: ['heading', 'paragraph'] }), Underline, Link, VueComponent.extend({ name: 'vueComponent', group: 'block', draggable: true, addAttributes() { return { src: { default: '123', } } }, } ), ], content: props.modelValue, onUpdate: ({ editor }) => { emit('update:modelValue', editor.getHTML()) }, editable: props.locked ? false : store.admin }) const sendDataToExtension = async (editor, event) => { // 触发事件时执行 ... state.src = '123' editor.chain().focus().insertContent('<vue-component/>').run() } </script>
对应的Vue组件
<script setup> import {NodeViewWrapper} from '@tiptap/vue-3' const props = defineProps({ node: { type: Object, required: true }, updateAttributes: { type: Function, required: true, } }) </script> <template> <node-view-wrapper class="vue-component" data-drag-handle=""> <p>{{ node.attrs.src }}</p> </node-view-wrapper> </template>
问题现象
- 当设置
src的默认值为固定字符串default: '123'时,属性能正常传递到组件。 - 若将默认值改为响应式对象的属性
default: state.src,或尝试通过insertContent的第二个参数传递属性时,src最终变为undefined。
解决方案
方法1:插入组件时在HTML标签中直接携带属性
insertContent的第二个参数并非用于传递节点属性,正确的做法是直接在HTML字符串中写入属性:
const sendDataToExtension = async (editor, event) => { state.src = '123' editor.chain().focus().insertContent(`<vue-component src="${state.src}"/>`).run() }
方法2:使用insertNode方法精准传递节点属性
相比插入HTML字符串,insertNode能更明确地控制节点类型和属性,避免解析问题:
const sendDataToExtension = async (editor, event) => { state.src = '123' editor.chain().focus().insertNode({ type: 'vueComponent', // 对应扩展中定义的name字段 attrs: { src: state.src } }).run() }
关键注意事项
- 不要将响应式值放在扩展的
addAttributes.default中:扩展初始化(编辑器创建时)state可能未完成初始化,且后续响应式更新不会同步到默认值——因为addAttributes仅在扩展定义时执行一次。 - 更新已插入组件的属性:若后续需要修改已渲染组件的
src值,可使用组件接收的updateAttributes方法:// 在自定义Vue组件内触发更新 props.updateAttributes({ src: '新的响应式值' })
内容的提问来源于stack exchange,提问作者Artur Müller Romanov
相关产品推荐
相关产品推荐

