使用 Vue 创建节点视图
如果你习惯使用 Vue,单纯用 Vanilla JavaScript 可能感觉比较复杂。好消息是:你也可以在节点视图中使用常规的 Vue 组件。只需要知道一点点相关知识,下面我们逐步讲解。
渲染 Vue 组件
在编辑器内部渲染 Vue 组件的步骤如下:
- 创建节点扩展
- 创建一个 Vue 组件
- 将该组件传递给提供的
VueNodeViewRenderer - 使用
addNodeView()注册 - 配置 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*'(这是我们上面示例中的设置)。
NodeViewWrapper 和 NodeViewContent 组件会渲染 <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 元素即可。