项目

tiptap 使用 React 渲染视图节点

引言

如果你习惯于使用 React 工作,那么使用纯 JavaScript 可能会感觉复杂。好消息是:你也可以在 Node 视图中使用普通的 React 组件。只需要了解一些基本知识,接下来我们将逐一讲解。

渲染 React 组件

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

  1. 创建自定义扩展
  2. 创建 React 组件
  3. 将组件传递给提供的 ReactNodeViewRenderer
  4. 使用 addNodeView() 注册它
  5. 配置 Tiptap 使用新的 Node 扩展

这是你的 Node 扩展可能的样子:

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>

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

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

这个组件还不与编辑器交互。现在是时候连接它们了。

访问节点属性

在 Node 扩展中使用的 ReactNodeViewRenderer 会将一些非常有用的属性传递给你的自定义 React 组件。其中一个是 node 属性。假设你在扩展中添加了一个名为 count 的属性(如上例所示),你可以像这样访问它:

props.node.attrs.count;

更新节点属性

借助传递给组件的 updateAttributes 属性,甚至可以在组件内部更新节点属性。将更新后的属性对象传递给 updateAttributes 属性:

export default (props) => {
  const increase = () => {
    props.updateAttributes({
      count: props.node.attrs.count + 1,
    });
  };

  // ...
};

是的,这一切都是实时的。通信相当顺畅,不是吗?

添加可编辑内容

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

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 属性,可以移除或传入其他类名。尝试下面的例子:

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

请记住,这里的可编辑内容由 Tiptap 渲染。这意味着你需要告诉允许什么样的内容,例如在扩展中使用 content: 'inline*' (如上面示例所示)。

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

更改 Node 视图的默认内容标签

ReactNodeViewRenderer 默认会在渲染的 Node 视图中包裹一个 div。如果你想更改这个节点的类型,可以在 ReactNodeViewRenderer 选项中设置 contentDOMElementTag

// 这将把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" });
  },
});

所有可用属性

这是你能期待的所有属性列表:

editor

编辑器实例

node

当前节点

decorations

装饰数组

selected

当当前 Node 视图有 NodeSelection 时为 true

extension

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

getPos()

获取当前节点的文档位置

updateAttributes()

更新当前节点的属性

deleteNode()

删除当前节点

拖放

要使 Node 视图可拖动,将 draggable 设置为 true 在扩展中,并为希望作为拖动处理的 DOM 元素添加 data-drag-handle 属性。

在本文档中