常见问题
当我将编辑器的内容复制到文本框时,得到了一堆换行符
在 Tiptap 中,默认情况下,剪贴板文本序列化器设置为在段落之间生成 2 个换行符(就像你在 Markdown 中所做的那样)。
所以你粘贴的内容看起来是这样的:
这是一个段落。
这是另一个段落。而你可能希望它看起来是这样的(段落之间没有额外换行符):
这是一个段落。
这是另一个段落。要实现这一点,你需要将 clipboardTextSerializer 更改为使用单个换行符而不是两个。
像这样:
new Editor({
// 其他选项
coreExtensionOptions: {
clipboardTextSerializer: {
blockSeparator: '\n',
},
},
})这将使剪贴板序列化器使用单个换行符作为块之间的分隔符。
我的拖放功能无法正常工作
一些库,比如 react-dnd 或 react-beautiful-dnd 可能会通过全局注册干扰 Tiptap 的拖放功能。
如果你正在使用这些库中的一个,你可能需要禁用它们(或者至少限制它们监听的元素),以使编辑器的拖放功能正常工作。
为什么同时有 parseHTML 和 renderHTML
parseHTML 和 renderHTML 可以被视为相反的操作:
parseHTML: HTML -> JSON,将 HTML 表示解析为 JSON。renderHTML: JSON -> HTML,将 JSON 表示输出为 HTML 以在编辑器中呈现。
这使得 Tiptap 能够在内容表示上非常灵活。你可以将内容定义为 JSON,然后将其渲染为 HTML,或你可以将内容定义为 HTML,然后将其解析为 JSON。
此外,parseHTML 和 renderHTML 也可以在不同的上下文中使用:
renderHTML 在 复制事件 中使用,因为你从编辑器中复制的内容需要序列化为 HTML 以进入剪贴板。
parseHTML 在 粘贴事件 中使用,因为你剪贴板中的 HTML 被序列化为 HTML,需要解析为 JSON。
在初次渲染时,如果你的内容被定义为 JSON,parseHTML 将完全被跳过,仅在粘贴时使用。
而你的 renderHTML 方法确定内容在编辑器内的 HTML 表示方式。
renderHTML 可以在编辑器视图中通过节点视图和标记视图被覆盖,以允许对节点和标记的自定义渲染。
我想用 Tiptap 编辑 HTML 内容
Tiptap 是基于 Prosemirror构建的,并不是一个任意的 HTML 编辑器,它是一个富文本编辑器,需要对正在编辑的 HTML 拥有完全的控制权来进行更改。Prosemirror 通过尝试以符合模式的方式解析内容来实现这一点(该模式源于你作为 Tiptap 扩展指定的节点和标记),这意味着不符合模式的内容将会丢失。这是一个权衡,Prosemirror 可以接受相当数量的 HTML 内容,并将其解析为结构化格式,但无法可靠地处理任意 HTML(在接受内容时比较宽松,但在输出时却很严格)。
一个常见的情况是试图嵌套不同类型的标记,如:<span class="my-class"><span style="color: red">可编辑文本</span></span> 这两个标记无法这样嵌套,Prosemirror 将通过丢弃其中一个来试图修复这一点,以遵循标记无法相互包裹的规则。要解决此问题,输入到编辑器的 HTML 应该采用一个带有多个属性的元素的格式,如:<span class="my-class" style="color: red">可编辑文本</span>,Prosemirror 将正确解析这一格式,因为它试图将两个标记应用于文本。
在 Prosemirror 中没有配置此行为的方法,因为解析任意 HTML 已经相当复杂。根据你试图解析的 HTML 来源,你可以:
- 依赖默认行为并丢弃未知内容
- 尝试自己用自定义 HTML 解析器解析 HTML,并使其符合 Prosemirror 的期望(例如合并
<span>)
React 上下文在 NodeViews 中无法工作
要在 NodeView 中使用 React 上下文,你需要用上下文提供者包装 EditorContent 组件。在 nodeview 中,上下文应该可以在 NodeView 组件中使用。
import React from 'react'
import { EditorContent } from '@tiptap/react'
const TiptapEditor = ({ editor }) => {
return (
<MyContext.Provider value={{ foo: 'bar' }}>
<EditorContent editor={editor} />
</MyContext.Provider>
)
}为什么使用 React Node View 时会有额外的 div
这些 div 存在的原因是 prosemirror 期望同步生成一个节点视图,而 React 只能异步渲染。因此,我们注入一个元素,然后让 React 异步渲染到该元素中。这导致在 DOM 中有一个包装 div。
同样,当使用 NodeViewContent 时,有一个由 React 创建的元素,然后 Prosemirror 渲染到该元素中。这必须存在作为从 React 到 Prosemirror 的交接,因为 React 的默认行为是清除它正在渲染的元素,我们需要确保 React 不会销毁 prosemirror 正在尝试渲染富文本的元素。
因此,可以说,由于 React 的工作方式,没有好的方法去除这些中间元素。你只能使用 JS NodeView API 或 Vue,因为这两者的渲染方式更为合理。