返回

Vue3 中 TipTap 编辑器如何循环使用?

vue.js

Vue3 中 TipTap 编辑器循环使用避坑指南

在 Vue3 项目中,借助 TipTap 富文本编辑器,我们可以轻松创建功能丰富的编辑区域。然而,当需要动态生成多个可编辑区域,也就是在循环中使用 TipTap 时,你可能会遇到一些棘手的问题,例如编辑器内容显示错乱,或者菜单栏重复出现。

这些问题的根源在于 TipTap 编辑器实例和编辑器内容之间绑定关系的处理。如果在循环中直接使用同一个 editor 实例,所有循环项都会指向同一个实例,最终导致内容显示异常。

如何优雅地解决循环使用 TipTap 出现的难题?

为了解决这个问题,我们需要为每个循环项创建一个独立的 TipTap 编辑器实例,确保每个编辑区域都拥有独立的实例和内容绑定。

1. 封装 TipTap 编辑器组件

为了更方便地管理每个编辑器实例,我们可以创建一个独立的 TipTap 编辑器组件:

// SMSTemplateEditor.vue
<template>
  <div>
    <editor-menubar :editor="editor" />
    <editor-content :editor="editor" />
  </div>
</template>

<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { useEditor, EditorContent } from '@tiptap/vue-3';
import StarterKit from '@tiptap/starter-kit';
import EditorMenubar from '@/components/forms/plugins/editor/EditorMenubar.vue';

const props = defineProps<{
  content: string;
}>();

const editor = useEditor({
  extensions: [StarterKit],
  content: props.content,
});

onMounted(() => {
  // 在此处你可以进行其他初始化操作
});
</script>

在这个名为 SMSTemplateEditor 的组件中,我们引入了 useEditor 方法来创建 TipTap 编辑器实例,并使用 editor-menubareditor-content 组件分别渲染菜单栏和编辑区域。通过 props 传入 content,我们可以灵活控制每个编辑器实例的初始内容。

2. 在循环中引入编辑器组件

现在,你可以在主组件的循环中使用 SMSTemplateEditor 组件,为每个循环项生成独立的编辑器实例:

<template>
  <v-row v-for="(template, index) in SMSTemplates" :key="index">
    <v-col cols="12" sm="12">
      <SMSTemplateEditor v-model="template.content" />
    </v-col>
  </v-row>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import SMSTemplateEditor from './SMSTemplateEditor.vue';

const SMSTemplates = ref([
  { content: 'Template 1 content' },
  { content: 'Template 2 content' },
  // ... other templates
]);
</script>

在上面的代码中,我们使用 v-for 指令循环渲染 SMSTemplateEditor 组件,并将 template.content 绑定到组件的 v-model 属性上。这样,每个 SMSTemplateEditor 实例都会绑定到对应的 template.content,确保内容正确显示和编辑,避免出现冲突。

通过以上两个步骤,我们成功地解决了在 Vue3 中循环使用 TipTap 编辑器遇到的问题,确保每个循环项都拥有独立的编辑器实例,为用户提供流畅的编辑体验。

常见问题解答

  1. 问: 使用 v-model 绑定数据后,编辑器内容不更新怎么办?

    答: 确保 SMSTemplateEditor 组件的 content 属性定义为 props,并在组件内部使用 props.content 访问。

  2. 问: 如何自定义编辑器菜单栏?

    答: 你可以自定义 EditorMenubar 组件,并在其中使用 TipTap 提供的 Extension API 添加或移除菜单项。

  3. 问: 如何获取编辑器实例?

    答: 你可以通过 editor 变量访问 SMSTemplateEditor 组件内部的编辑器实例,并调用 TipTap 提供的 API 进行操作。

  4. 问: 如何监听编辑器内容变化?

    答: 你可以使用 editor.on('update', (props) => {}) 方法监听编辑器内容变化事件,并在回调函数中处理更新后的内容。

  5. 问: 如何在编辑器中插入自定义节点?

    答: 你可以使用 TipTap 提供的 Node API 定义自定义节点,并通过 editor.chain().insertContent({ type: 'your-custom-node' }).run() 方法插入到编辑器中。