tiptap 可交互节点视图
引言
节点视图就像切片面包一样出色,至少对于喜欢定制(和面包)的人来说是这样。通过节点视图,您可以在编辑器中添加交互式的节点。这几乎可以是任何东西。如果你能用 JavaScript 写出来,你就可以在你的编辑器中使用它。
节点视图极大地提升了编辑器内的用户体验,但也可以用于只读的 Tiptap 实例中。它们与 HTML 输出设计上无关,因此你完全控制着编辑器内的体验和输出。
不同类型的节点视图
根据你想要构建的内容,节点视图的工作方式略有不同,它们可能具有特定的能力,但也可能存在一些陷阱。主要问题是:你希望自定义节点看起来像什么?
可编辑文本
是的,节点视图可以包含可编辑文本,就像常规节点一样。这很简单。光标的行为会像你期望的常规节点那样。现有的命令与这些节点配合得很好。
<div class="Prosemirror" contenteditable="true">
<p>text</p>
<node-view>text</node-view>
<p>text</p>
</div>
这就是TaskItem
节点的工作原理。
非可编辑文本
节点也可以有不可编辑的文本。光标无法跳入其中,而且你也不想让它这么做。
Tiptap 默认为这些添加了contenteditable="false"
属性。
<div class="Prosemirror" contenteditable="true">
<p>text</p>
<node-view contenteditable="false">text</node-view>
<p>text</p>
</div>
你可以这样渲染提及,它们不应该可编辑。用户可以添加或删除它们,但不能删除单个字符。
Statamic 在他们的 Bard 编辑器中使用这种方式,它在 Tiptap 中渲染复杂的模块,这些模块可以有自己的文本输入。
混合内容
你甚至可以混合非可编辑和可编辑的文本。这对于构建复杂内容非常有用,同时仍然可以在可编辑内容中使用粗体、斜体等标记。
但是,如果节点视图中有其他不可编辑文本元素,光标可能会跳到那里。你可以通过手动为节点视图中的特定部分添加 contenteditable="false"
来改进这一点。
<div class="Prosemirror" contenteditable="true">
<p>text</p>
<node-view>
<div contenteditable="false">非可编辑文本</div>
<div>可编辑文本</div>
</node-view>
<p>text</p>
</div>
格式化
但是,当你 访问编辑器内容 时会发生什么呢?如果你使用的是 HTML,你需要告诉 Tiptap 如何序列化你的节点。
编辑器不会导出渲染后的 JavaScript 节点,而且在很多情况下,你也不希望这样做。
假设你有一个节点视图,让用户添加视频播放器并配置外观(自动播放、控制等)。你希望界面在编辑器中完成这些操作,而不是在编辑器的输出中。编辑器的输出可能只包含视频播放器。
我知道,我知道,这并不简单。请记住,你完全控制着编辑器内的渲染和输出。
警告 如果存储 JSON 呢?
这不适用于 JSON。在 JSON 中,所有内容都作为对象存储。不需要配置从 JSON 到 HTML 的 “转换” 。
渲染 HTML
好的,你已经设置了带有交互式节点视图的节点,现在你想控制输出。即使你的节点视图很复杂,渲染后的 HTML 也可以很简单:
renderHTML({ HTMLAttributes }) {
return ['my-custom-node', mergeAttributes(HTMLAttributes)]
},
确保它是可区分的,以便更容易从 HTML 中恢复内容。如果你只需要类似 <div>
的通用标记,请考虑添加一个 data-type="my-custom-node"
属性。
解析 HTML
恢复内容时也是如此。你可以配置你期望的标记,这可以与节点视图的标记完全无关。它只需要包含你想恢复的所有信息。
如果注册了属性,属性会自动恢复 [1]。
// 输入: <my-custom-node count="1"></my-custom-node>
parseHTML() {
return [{
tag: 'my-custom-node',
}]
},
渲染 JavaScript/Vue/React
但如果想渲染实际的 JavaScript/Vue/React 代码呢?考虑使用 Tiptap 来渲染输出。只需将编辑器设置为 editable: false
,没人会注意到你在用一个编辑器来渲染内容。:-)
[1]: 如果你通过 addAttributes
注册了属性,它们会自动恢复。