项目

tiptap 使用 Vue 渲染视图节点

引言

如果你习惯使用 Vue 工作,那么用原生 JavaScript 可能会感觉复杂。好消息是:你也可以在节点视图中使用常规的 Vue 组件。只需要了解一些基本知识,接下来我们会逐一讲解。

渲染 Vue 组件

要在编辑器中渲染 Vue 组件,你需要做以下步骤:

  1. 创建节点扩展
  2. 创建 Vue 组件
  3. 将该组件传递给提供的VueNodeViewRenderer
  4. 通过addNodeView()注册它
  5. 配置 Tiptap 使用新的节点扩展

你的节点扩展可能看起来像这样:

import { Node } from "@tiptap/core";
import { VueNodeViewRenderer } from "@tiptap/vue-2";
import Component from "./Component.vue";

export default Node.create({
  // 配置...

  addNodeView() {
    return VueNodeViewRenderer(Component);
  },
});

为了让这个工作,需要一点魔法。别担心,我们提供了一个启动器组件,你可以轻松开始使用。别忘了在自定义 Vue 组件中添加它,如下所示:

<template>
  <node-view-wrapper> Vue组件 </node-view-wrapper>
</template>

明白了吗?现在让我们实际操作一下。你可以复制下面的示例开始:

https://embed.tiptap.dev/preview/GuideNodeViews/VueComponent

然而,这个组件还不与编辑器交互。现在该连接起来了。

访问节点属性

在节点扩展中使用的 VueNodeViewRenderer 会将一些非常有用的属性传给你的自定义 Vue 组件。其中一个是 node 属性。在组件中添加这个片段以便直接访问节点:

props: {
  node: {
    type: Object,
    required: true,
  },
},

这样你就可以在 Vue 组件中访问节点属性了。假设你在扩展中添加了一个名为 count 的属性(如上例所示),你可以这样访问:

this.node.attrs.count;

更新节点属性

借助传给组件的 updateAttributes 属性,你甚至可以在节点中更新属性。在组件中添加以下片段:

props: {
  updateAttributes: {
    type: Function,
    required: true,
  },
},

然后将更新后的属性对象传递给函数:

this.updateAttributes({
  count: this.node.attrs.count + 1,
});

而且,这一切都是响应式的。是不是很无缝的通信呢?

添加可编辑内容

还有一个名为 NodeViewContent 的组件,可以帮助你在节点视图中添加可编辑内容。看个例子:

<template>
  <node-view-wrapper class="dom">
    <node-view-content class="content-dom" />
  </node-view-wrapper>
</template>

<script>
  import { NodeViewWrapper, NodeViewContent } from "@tiptap/vue-2";

  export default {
    components: {
      NodeViewWrapper,
      NodeViewContent,
    },
  };
</script>

你不需要添加这些 class 属性,可以删除或使用其他类名。尝试下面的例子:

https://embed.tiptap.dev/preview/GuideNodeViews/VueComponentContent

请记住,这部分内容由 Tiptap 渲染。这意味着你需要指定允许什么样的内容,例如在节点扩展中使用 content: 'inline*'(如上例所示)。

NodeViewWrapperNodeViewContent 组件渲染 <div> HTML 标签(对于行内节点是 <span> ),但你可以更改这个。例如,<node-view-content as="p"> 应该渲染一个段落。不过有一个限制:这个标签在运行时不能改变。

所有可用的属性

对于高级用法,我们还会向组件传递更多属性。

editor

编辑器实例。

node

访问当前节点。

decorations

装饰数组。

selected

当当前节点视图有 NodeSelection 时,设置为 true

extension

访问节点扩展,例如获取选项。

getPos()

获取当前节点的文档位置。

updateAttributes()

更新当前节点的属性。

deleteNode()

删除当前节点。

以下是你可以期待的所有属性完整列表:

<template>
  <node-view-wrapper />
</template>

<script>
  import { NodeViewWrapper } from "@tiptap/vue-2";

  export default {
    components: {
      NodeViewWrapper,
    },

    props: {
      // 编辑器实例
      editor: {
        type: Object,
      },

      // 当前节点
      node: {
        type: Object,
      },

      // 装饰数组
      decorations: {
        type: Array,
      },

      // 当前节点视图有`NodeSelection`时为`true`
      selected: {
        type: Boolean,
      },

      // 节点扩展的访问,例如获取选项
      extension: {
        type: Object,
      },

      // 获取当前节点的文档位置
      getPos: {
        type: Function,
      },

      // 更新当前节点的属性
      updateAttributes: {
        type: Function,
      },

      // 删除当前节点
      deleteNode: {
        type: Function,
      },
    },
  };
</script>

如果你只想拥有所有(并带有 TypeScript 支持),你可以导入所有的属性:

// Vue 3
import { defineComponent } from 'vue'
import { nodeViewProps } from '@tiptap/vue-3'
export default defineComponent({
  props: nodeViewProps,
})

// Vue 2
import Vue from 'vue'
import { nodeViewProps } from '@tiptap/vue-2'
export default Vue.extend({
  props: nodeViewProps,
})

拖放

要使节点视图可拖动,将扩展的 draggable 属性设置为 true,并在作为拖动处理程序的 DOM 元素上添加 data-drag-handle 属性。

https://embed.tiptap.dev/preview/GuideNodeViews/DragHandle

在本文档中