使用 React 的节点视图
如果您习惯于使用 React 工作,使用普通 JavaScript 可能会感觉复杂。好消息是:您也可以在节点视图中使用常规的 React 组件。您只需知道一点小知识,让我们逐步来看。
渲染 React 组件
要在编辑器中渲染 React 组件,您需要执行以下操作:
- 创建一个节点扩展
- 创建一个 React 组件
- 将该组件传递给提供的
ReactNodeViewRenderer - 使用
addNodeView()注册 - 配置 Tiptap 使用您的新节点扩展
您的节点扩展可能看起来像这样:
import { Node } from '@tiptap/core'
import { ReactNodeViewRenderer } from '@tiptap/react'
import Component from './Component.jsx'
export default Node.create({
// 配置 …
addNodeView() {
return ReactNodeViewRenderer(Component)
},
})要使其正常工作需要一点魔法。但不要担心,我们提供了一个可以帮助您轻松入门的包装组件。不要忘记将其添加到您的自定义 React 组件中,如下所示:
<NodeViewWrapper className="react-component">React 组件</NodeViewWrapper>明白了吗?让我们看看实际效果。请随意复制以下示例开始吧。
不过,该组件并不会与编辑器交互。是时候将其连接起来了。
访问节点属性
您在节点扩展中使用的 ReactNodeViewRenderer,向您的自定义 React 组件传递了一些非常有用的 props。其中之一是 node prop。假设您已向节点扩展添加了名为 count 的属性(就像我们在上面的示例中做的那样),您可以这样访问它:
props.node.attrs.count更新节点属性
您甚至可以通过节点更新节点属性,借助传递给您的组件的 updateAttributes prop。将更新后的属性对象传递给 updateAttributes prop:
export default (props) => {
const increase = () => {
props.updateAttributes({
count: props.node.attrs.count + 1,
})
}
// …
}是的,这一切都是响应式的。这是非常无缝的通信,不是吗?
添加可编辑内容
还有一个名为 NodeViewContent 的组件,可以帮助您向节点视图添加可编辑内容。以下是一个示例:
import React from 'react'
import { NodeViewWrapper, NodeViewContent } from '@tiptap/react'
export default () => {
return (
<NodeViewWrapper className="react-component">
<span className="label" contentEditable={false}>
React 组件
</span>
<NodeViewContent className="content" />
</NodeViewWrapper>
)
}您不需要添加这些 className 属性,可以随意删除它们或传递其他类名。在以下示例中试试:
请记住,这些内容是由 Tiptap 渲染的。这意味着您需要告诉允许什么类型的内容,例如在您的节点扩展中使用 content: 'inline*'(这是我们在上面的示例中使用的)。
NodeViewWrapper 和 NodeViewContent 组件渲染一个 <div> HTML 标签(对于行内节点则是 <span>),但您可以更改它。例如 <NodeViewContent as="p"> 应该渲染一个段落。不过有一个限制:该标签在运行时必须不可更改。
更改节点视图的默认内容标签
默认情况下,ReactNodeViewRenderer 渲染的节点视图将始终包含一个包裹的 div。如果您想更改此节点的类型,可以将 contentDOMElementTag 添加到 ReactNodeViewRenderer 选项:
// 这将把 div 转变为 header 标签
return ReactNodeViewRenderer(Component, { contentDOMElementTag: 'header' })更改包裹的 DOM 元素
要更改包裹 DOM 元素的标签,您可以在 ReactNodeViewRenderer 函数上使用 contentDOMElementTag 选项来更改默认标签名称。
import { Node } from '@tiptap/core'
import { ReactNodeViewRenderer } from '@tiptap/react'
import Component from './Component.jsx'
export default Node.create({
// 配置 …
addNodeView() {
return ReactNodeViewRenderer(Component, { contentDOMElementTag: 'main' })
},
})所有可用的 props
以下是您可以期待的 props 完整列表:
| Prop | 描述 |
|---|---|
| editor | 编辑器实例 |
| node | 当前节点 |
| decorations | 装饰数组 |
| selected | 当当前节点视图有 NodeSelection 时为 true |
| extension | 访问节点扩展,例如获取选项 |
| getPos() | 获取当前节点的文档位置 |
| updateAttributes() | 更新当前节点的属性 |
| deleteNode() | 删除当前节点 |
拖动
要使您的节点视图可拖动,请在扩展中设置 draggable: true,并将 data-drag-handle 添加到应该作为拖动句柄的 DOM 元素。