@tiptap/core vs quill vs slate
现代 Web 应用中的富文本编辑器架构选型
@tiptap/corequillslate类似的npm包:

现代 Web 应用中的富文本编辑器架构选型

@tiptap/core、quill 和 slate 都是用于在 Web 应用中构建富文本编辑器的流行库,但它们的设计哲学和底层架构截然不同。@tiptap/core 是一个无头(headless)编辑器框架,基于 ProseMirror 构建,提供极高的可扩展性而不绑定 UI。quill 是一个开箱即用的富文本编辑器,拥有自己的 DOM 结构和 Delta 数据格式,强调快速集成和标准功能。slate 则是一个完全可定制的 React 编辑器框架,没有预设的 schema,允许开发者完全控制数据结构和渲染逻辑。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
@tiptap/core13,818,73438,8113.3 MB9118 天前MIT
quill3,803,71047,3803.04 MB6632 年前BSD-3-Clause
slate1,721,40231,7432.62 MB64 天前MIT

@tiptap/core vs Quill vs Slate: 架构、扩展性与数据模型深度对比

@tiptap/core、quill 和 slate 都旨在解决 Web 应用中的富文本编辑问题,但它们的实现路径完全不同。@tiptap/core 侧重于无头架构和扩展性,quill 侧重于开箱即用和标准化,而 slate 侧重于 React 原生和完全定制。让我们从架构师的角度深入对比它们如何处理核心问题。

🏗️ 核心架构:无头框架 vs 完整方案 vs React 原生

@tiptap/core 是一个无头编辑器,它只提供逻辑层,不渲染任何 UI。

  • 基于 ProseMirror 构建,拥有强大的文档模型。
  • 你需要自己编写或使用现成的 UI 组件来连接编辑器。
// tiptap: 初始化编辑器实例
import { useEditor } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'

const EditorComponent = () => {
  const editor = useEditor({
    extensions: [StarterKit],
    content: '<p>Hello World</p>',
  })
  return null // 你需要自己渲染 UI
}

quill 是一个完整的编辑器解决方案,包含 DOM 编辑器和工具栏。

  • 直接操作 DOM 节点,内部管理选区和格式。
  • 提供内置主题(如 Snow 和 Bubble),快速集成。
// quill: 初始化编辑器实例
import Quill from 'quill'

const editor = new Quill('#editor-container', {
  theme: 'snow',
  modules: {
    toolbar: ['#toolbar-container']
  }
})
// 直接挂载到 DOM 元素

slate 是一个 React 原生编辑器框架,没有预设架构。

  • 完全由 React 组件构成,数据即状态。
  • 没有内置工具栏或按钮,一切都需要自己实现。
// slate: 初始化编辑器实例
import { createEditor } from 'slate'
import { Slate, Editable, withReact } from 'slate-react'

const editor = withReact(createEditor())

const EditorComponent = () => {
  const [value, setValue] = useState(initialValue)
  return (
    <Slate editor={editor} initialValue={value} onChange={setValue}>
      <Editable />
    </Slate>
  )
}

🧩 扩展与定制:扩展系统 vs 模块系统 vs 完全控制

@tiptap/core 使用扩展(Extensions)系统来添加功能。

  • 每个功能(如加粗、列表)都是一个独立的扩展。
  • 可以轻松启用或禁用特定功能,无需修改核心代码。
// tiptap: 添加扩展
import Bold from '@tiptap/extension-bold'

const editor = useEditor({
  extensions: [
    StarterKit,
    Bold.configure({ HTMLAttributes: { class: 'my-bold' } })
  ],
})

quill 使用模块(Modules)系统来配置功能。

  • 通过配置对象启用工具栏、历史记录等功能。
  • 自定义格式需要注册新的 Blot 类型,较为复杂。
// quill: 配置模块
const quill = new Quill('#editor', {
  modules: {
    toolbar: [['bold', 'italic'], ['link']],
    history: { delay: 2000, maxStack: 500 }
  }
})

slate 没有内置的扩展系统,一切靠代码组合。

  • 通过高阶函数(如 withReact)或自定义插件增强编辑器。
  • 你可以完全重写插入、删除或渲染的逻辑。
// slate: 自定义插件
const withLinks = editor => {
  const { insertData } = editor
  editor.insertData = data => {
    // 自定义数据插入逻辑
    insertData(data)
  }
  return editor
}

📄 数据模型:JSON 文档 vs Delta 格式 vs 自定义节点

@tiptap/core 使用 ProseMirror 的 JSON 文档模型。

  • 数据是结构化的 JSON 树,易于序列化和验证。
  • 支持协同编辑的基础架构。
// tiptap: 获取 JSON 内容
const jsonContent = editor.getJSON()
// { type: "doc", content: [{ type: "paragraph", content: [...] }] }

quill 使用 Delta 格式来表示内容和变更。

  • Delta 是一种操作序列,描述如何从空文档构建当前内容。
  • 适合记录历史操作,但结构不如纯 JSON 直观。
// quill: 获取 Delta 内容
const delta = quill.getContents()
// { ops: [{ insert: "Hello" }, { insert: "World", attributes: { bold: true } }] }

slate 使用自定义的节点树结构,由开发者定义。

  • 没有固定格式,你可以决定节点长什么样。
  • 非常适合需要特殊数据结构(如嵌套块)的场景。
// slate: 自定义节点结构
const initialValue = [
  {
    type: 'paragraph',
    children: [{ text: 'A line of text in a paragraph.' }],
  },
]

⚛️ React 集成:官方 Hook vs 外部封装 vs 原生组件

@tiptap/core 提供官方的 @tiptap/react 包。

  • 提供 useEditor Hook 自动处理生命周期。
  • 与 React 状态同步良好,但仍需手动管理 UI 状态。
// tiptap: React Hook
const { editor } = useEditor({
  extensions: [StarterKit],
  content: contentState,
})

quill 没有官方 React 支持,通常使用封装库。

  • 需要手动处理 DOM 实例和 React 渲染的同步。
  • 容易出现受控组件与非受控组件的冲突。
// quill: React 中手动初始化
useEffect(() => {
  const quill = new Quill('#editor', { theme: 'snow' })
  quill.on('text-change', () => { /* sync state */ })
}, [])

slate 是专为 React 设计的,完全基于组件。

  • 编辑器状态就是 React 状态,天然同步。
  • 渲染逻辑完全由 React 组件控制,易于定制。
// slate: 原生 React 组件
<Slate editor={editor} initialValue={value} onChange={setValue}>
  <Editable />
</Slate>

🌱 相似之处:共同的基础能力

尽管架构不同,这三个库都解决了富文本编辑的核心需求。以下是它们的关键重叠点:

1. 📝 基础文本格式支持

  • 都支持加粗、斜体、列表等基础格式。
  • 提供 API 来编程式地修改选区内容。
// 所有库都支持类似操作
// tiptap: editor.chain().focus().toggleBold().run()
// quill: quill.formatText(index, length, { bold: true })
// slate: Transforms.mark(editor, { type: 'bold' })

2. 🔄 历史记录管理

  • 都内置了撤销和重做功能。
  • 通过内部栈管理操作历史。
// 所有库都支持撤销
// tiptap: editor.chain().focus().undo().run()
// quill: quill.history.undo()
// slate: editor.undo()

3. 🌐 序列化与导出

  • 都支持将内容导出为 HTML 或 JSON。
  • 便于保存到后端或进行静态渲染。
// 所有库都支持 HTML 导出
// tiptap: editor.getHTML()
// quill: quill.root.innerHTML
// slate: 需自行实现序列化逻辑

📊 总结:关键差异对比

特性@tiptap/corequillslate
架构类型🧠 无头框架 (ProseMirror)📦 完整方案 (DOM)⚛️ React 原生框架
数据格式📄 JSON 文档树📏 Delta 操作序列🧩 自定义节点树
UI 控制🎨 完全自定义🖌️ 内置主题🛠️ 完全自定义
React 支持✅ 官方 Hook⚠️ 需手动封装✅ 原生组件
学习曲线📈 中等📉 低📈 高
适用场景复杂协作、定制 UI快速集成、标准需求高度定制、React 深度集成

💡 最终建议

@tiptap/core 就像是一个强大的发动机 🚗——它提供了驱动编辑器所需的核心动力,但你需要自己制造车身。适合需要长期维护、复杂功能(如协同编辑)且希望 UI 完全定制的企业级应用。

quill 就像是一辆成品自行车 🚲——开箱即用,适合短途出行。适合博客、评论区等需要快速上线、功能标准且不需要深度定制的项目。

slate 就像是一套乐高积木 🧱——你可以搭建任何形状,但需要自己设计结构。适合 React 技术栈深厚、需要特殊数据模型或交互逻辑的创新型产品。

核心思考:选择编辑器不仅仅是选择一个库,而是选择一种数据管理方式。如果你重视数据结构的稳定性,选 @tiptap/core;如果你重视开发速度,选 quill;如果你重视 React 状态的一致性,选 slate。

如何选择: @tiptap/core vs quill vs slate

  • @tiptap/core:

    如果你需要一个稳定、功能强大且不绑定 UI 的编辑器,@tiptap/core 是最佳选择。它基于 ProseMirror,适合需要复杂协作功能或高度自定义工具栏的项目。选择它意味着你愿意花费时间配置扩展,但能获得长期的维护性和稳定性。

  • quill:

    如果你需要快速上线一个标准的博客或评论编辑器,quill 是最省力的方案。它内置了工具栏和主题,适合不需要深度定制数据结构的项目。选择它意味着接受其固定的 DOM 结构和 Delta 格式,以换取开发速度。

  • slate:

    如果你正在构建一个高度定制化的 React 应用,且需要完全控制编辑器的行为和数据结构,slate 提供了最大的灵活性。它适合需要特殊节点类型或复杂交互的场景。选择它意味着你需要自己处理更多底层逻辑,包括序列化和渲染细节。

@tiptap/core的README

@tiptap/core

Version Downloads License Sponsor

Introduction

Tiptap is a headless wrapper around ProseMirror – a toolkit for building rich text WYSIWYG editors, which is already in use at many well-known companies such as New York Times, The Guardian or Atlassian.

Official Documentation

Documentation can be found on the Tiptap website.

License

Tiptap is open sourced software licensed under the MIT license.