探索 Tiptap V3 的最新功能

使用 Vue 创建节点视图

如果你习惯使用 Vue,单纯用 Vanilla 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>

懂了吗?让我们一起来看看实际效果。以下示例可以直接复制使用。

不过,这个组件本身不与编辑器交互。现在就来连接它。

访问节点属性

你在节点扩展中使用的 VueNodeViewRenderer 会向你的自定义 Vue 组件传递一些非常有用的 props。其中之一是 node 属性。你可以将以下代码添加到你的 Vue 组件中,以便直接访问节点:

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

这样你就可以在 Vue 组件中访问节点的属性了。假设你在节点扩展中添加了一个 attribute,比如 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 属性,感觉可以删除或替换为其他类名。试试看下面的示例:

请记住,这些内容由 Tiptap 渲染。这意味着你需要在节点扩展中声明允许的内容类型,比如通过 content: 'inline*'(这是我们上面示例中的设置)。

NodeViewWrapperNodeViewContent 组件会渲染 <div>(内联节点为 <span>),但你也可以修改这个行为。例如 <node-view-content as="p"> 只要是块级标签就可以,默认会渲染为 <p>。但有个限制:标签在运行时不能更改。

所有可用的 props

对于高级用例,我们会传递更多 props 给你的组件。

editor

编辑器实例。

node

当前节点。

decorations

装饰的数组。

selected

当当前节点视图被选中(NodeSelection)时为 true

extension

访问节点扩展,例如用来获取配置项。

getPos()

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

updateAttributes()

更新当前节点的属性。

deleteNode()

删除当前节点。

以下是全部可用 props 的完整列表:

<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,
      },

      // 如果此节点视图被选中,则为 `true`
      selected: {
        type: Boolean,
      },

      // 访问节点扩展(例如获取配置)
      extension: {
        type: Object,
      },

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

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

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

如果你希望获取所有 props(支持 TypeScript),可以直接引入全部,例如:

// Vue 3
import { defineComponent } from 'src/content/editor/extensions/custom-extensions/node-views/vue.mdx'
import { nodeViewProps } from '@tiptap/vue-3'
export default defineComponent({
  props: nodeViewProps,
})

// Vue 2
import Vue from 'src/content/editor/extensions/custom-extensions/node-views/vue.mdx'
import { nodeViewProps } from '@tiptap/vue-2'
export default Vue.extend({
  props: nodeViewProps,
})

拖拽支持

若要让你的节点视图支持拖拽,只需在扩展中设置 draggable: true,并将 data-drag-handle 添加到作为拖拽手柄的 DOM 元素即可。