项目

tiptap 使用 JavaScript 渲染节点视图

引言

如果你习惯于不使用 Vue 或 React,但又想在你的 Node 视图中使用原生 JavaScript,那其实并不复杂。只需要了解一些基本知识,我们一步步来。

用 JavaScript 渲染节点视图

要在编辑器中渲染节点视图,你需要做以下步骤:

  1. 创建一个节点扩展
  2. 通过 addNodeView() 注册新的节点视图
  3. 编写渲染函数
  4. 配置 Tiptap 使用新的节点扩展

以下是节点扩展的示例代码:

import { Node } from "@tiptap/core";

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

  addNodeView() {
    return ({
      editor,
      node,
      getPos,
      HTMLAttributes,
      decorations,
      extension,
    }) => {
      const dom = document.createElement("div");

      dom.innerHTML = "你好,我是一个视图节点!";

      return {
        dom,
      };
    };
  },
});

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

点击这里查看演示

这个节点视图甚至能与编辑器交互。现在来看看如何实现这一点。

访问节点属性

编辑器会在渲染函数中传递一些有用的信息,其中 node 属性就是其中之一。你可以借此访问节点的属性。例如,如果你在一个节点扩展中添加了一个名为 count 的属性,可以通过以下方式获取:

addNodeView() {
  return ({ node }) => {
    console.log(node.attrs.count)

    // …
  }
}

更新节点属性

你还可以从节点视图中更新节点属性,利用 getPos 属性传递给你的渲染函数。通过调用一个新的事务,更新当前文档位置的属性:

addNodeView() {
  return ({ editor, node, getPos }) => {
    const { view } = editor

    // 创建一个按钮 ...
    const button = document.createElement('button')
    button.innerHTML = `这个按钮已被点击${node.attrs.count}次.`

    // ... 当按钮被点击时 ...
    button.addEventListener('click', () => {
      if (typeof getPos === 'function') {
        // ... 对当前文档位置发送事务,更新`count`属性 ...
        view.dispatch(view.state.tr.setNodeMarkup(getPos(), undefined, {
          count: node.attrs.count + 1,
        }))

        // ... 并将焦点重新设置到编辑器。
        editor.commands.focus()
      }
    })

    // ...
  }
}

这看起来可能有点复杂?如果你项目中已经使用了 React 或 Vue,考虑使用它们,会更轻松些。

添加可编辑内容

为了在节点视图中添加可编辑内容,你需要提供一个 contentDOM ,即内容容器元素。这是带有不可编辑文本和可编辑文本的简化版节点视图:

// 创建节点视图容器
const dom = document.createElement("div");

// 给包含文本的其他元素设置 `contentEditable = false`
const label = document.createElement("span");
label.innerHTML = "节点视图";
label.contentEditable = false;

// 创建内容容器
const content = document.createElement("div");

// 将所有元素附加到节点视图容器
dom.append(label, content);

return {
  // 返回节点视图容器 ...
  dom,
  // ... 和内容容器:
  contentDOM: content,
};

明白了吗?只要返回节点视图容器和内容容器即可。以下是上述示例的运行效果:

点击这里查看演示

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

在本文档中