第 1 章:Tiptap 简介
本章概述
欢迎来到 Tiptap 的世界!在本章中,我们将全面了解 Tiptap 是什么、它的核心特性、以及为什么它是构建现代富文本编辑器的最佳选择之一。
学习目标:
- 理解 Tiptap 的定位和设计理念
- 了解 Tiptap 的核心特性和优势
- 对比 Tiptap 与其他编辑器的区别
- 明确 Tiptap 的适用场景
- 了解 Tiptap 的生态系统
前置知识:
- 基础的 Web 开发知识(HTML、CSS、JavaScript)
- 了解现代前端框架(React、Vue 等)会有帮助,但不是必需的
预计学习时间: 20-30 分钟
1. 什么是 Tiptap
1.1 定义
Tiptap 是一个基于 ProseMirror 的无头(Headless) 、框架无关的富文本编辑器框架。
让我们拆解这个定义:
🎯 无头(Headless)
Tiptap 不提供预设的 UI 界面,你需要自己设计和实现编辑器的外观。
ini
传统编辑器(如 TinyMCE):
┌─────────────────────────────┐
│ [B] [I] [U] [链接] [图片] │ ← 预设的工具栏
├─────────────────────────────┤
│ │
│ 编辑区域 │
│ │
└─────────────────────────────┘
Tiptap(无头):
┌─────────────────────────────┐
│ │
│ 编辑区域(只有这个) │
│ │
└─────────────────────────────┘
↓
你可以自由设计任何 UI
优势:
- ✅ 完全自定义 UI 和交互
- ✅ 与你的设计系统完美融合
- ✅ 更小的包体积(不包含 UI 代码)
- ✅ 更灵活的用户体验
劣势:
- ❌ 需要自己实现 UI(工具栏、菜单等)
- ❌ 初期开发成本较高
🔧 框架无关(Framework Agnostic)
Tiptap 可以在任何前端框架中使用,也可以在原生 JavaScript 中使用。
支持的框架:
- ✅ React
- ✅ Vue 2 / Vue 3
- ✅ Angular
- ✅ Svelte
- ✅ Alpine.js
- ✅ Vanilla JavaScript
示例:
tsx
// React
import { useEditor, EditorContent } from '@tiptap/react'
// Vue 3
import { useEditor, EditorContent } from '@tiptap/vue-3'
// Vanilla JS
import { Editor } from '@tiptap/core'
🏗️ 基于 ProseMirror
Tiptap 是对 ProseMirror 的高级封装,提供了更友好的 API。
markdown
ProseMirror(底层)
↓
Tiptap(高级封装)
↓
你的应用
ProseMirror 的优势:
- 强大的文档模型(Schema)
- 高性能的渲染引擎
- 成熟的协同编辑支持
- 灵活的插件系统
Tiptap 的改进:
- 更简单的 API
- 更好的 TypeScript 支持
- 开箱即用的扩展
- 现代化的开发体验
1.2 核心理念
Tiptap 的设计遵循以下核心理念:
1. 可扩展性(Extensibility)
一切都是扩展(Extension)。
typescript
// 编辑器由扩展组成
const editor = new Editor({
extensions: [
Document, // 文档扩展
Paragraph, // 段落扩展
Text, // 文本扩展
Bold, // 加粗扩展
Italic, // 斜体扩展
// ... 更多扩展
],
})
好处:
- 按需加载,减小包体积
- 易于添加自定义功能
- 社区扩展丰富
2. 类型安全(Type Safety)
完整的 TypeScript 支持。
typescript
// 类型推断和检查
editor.chain()
.focus()
.toggleBold() // ✅ 类型安全
.toggleFoo() // ❌ 编译错误:方法不存在
.run()
3. 声明式 API(Declarative API)
使用链式调用执行命令。
typescript
// 声明式:描述"做什么"
editor.chain()
.focus()
.setHeading({ level: 1 })
.insertContent('Hello World')
.run()
// vs 命令式:描述"怎么做"
editor.focus()
const tr = editor.state.tr
tr.setNodeMarkup(0, schema.nodes.heading, { level: 1 })
// ... 更多底层操作
4. 协同优先(Collaboration First)
内置对协同编辑的支持。
typescript
import Collaboration from '@tiptap/extension-collaboration'
import * as Y from 'yjs'
const ydoc = new Y.Doc()
const editor = new Editor({
extensions: [
StarterKit,
Collaboration.configure({
document: ydoc,
}),
],
})
2. 为什么选择 Tiptap
2.1 核心优势
✨ 1. 现代化的开发体验
特点:
- 完整的 TypeScript 支持
- 优秀的文档和示例
- 活跃的社区和生态
- 持续的更新和维护
示例:
typescript
// 类型提示和自动补全
editor.chain()
.focus()
.toggle // ← IDE 会提示所有 toggle 开头的方法
.run()
🎨 2. 完全自定义的 UI
特点:
- 无预设 UI,完全由你控制
- 与任何 UI 库/框架集成
- 支持任何设计系统
示例:
tsx
// 使用 Material-UI
<Toolbar>
<IconButton onClick={() => editor.chain().focus().toggleBold().run()}>
<FormatBoldIcon />
</IconButton>
</Toolbar>
// 使用 Ant Design
<Space>
<Button onClick={() => editor.chain().focus().toggleBold().run()}>
<BoldOutlined />
</Button>
</Space>
// 使用 Tailwind CSS
<button
onClick={() => editor.chain().focus().toggleBold().run()}
className="px-4 py-2 bg-blue-500 text-white rounded"
>
Bold
</button>
🔌 3. 丰富的扩展生态
官方扩展:
- 100+ 个官方扩展
- 覆盖常见的编辑器功能
- 持续更新和维护
社区扩展:
- 数百个社区扩展
- 涵盖各种特殊需求
- 开源且可自定义
扩展分类:
| 类型 | 示例 | 数量 |
|---|---|---|
| Nodes(节点) | Paragraph, Heading, Image, Table | 20+ |
| Marks(标记) | Bold, Italic, Link, Highlight | 10+ |
| Extensions(功能) | History, Collaboration, Placeholder | 70+ |
🤝 4. 强大的协同编辑
特点:
- 基于 Y.js(CRDT)
- 支持实时协同
- 离线编辑和冲突解决
- 协作光标和用户状态
应用场景:
- 团队文档协作(类似 Google Docs)
- 实时笔记应用
- 协同编辑平台
⚡ 5. 高性能
优化:
- 虚拟 DOM 渲染
- 增量更新
- 懒加载扩展
- 优化的文档结构
性能对比:
makefile
文档大小: 10,000 字
操作: 插入 1,000 个字符
Tiptap: ~50ms
Draft.js: ~200ms
Slate: ~150ms
💡 注意: 性能数据仅供参考,实际性能取决于具体使用场景。
🛡️ 6. 类型安全
TypeScript 支持:
- 完整的类型定义
- 类型推断
- 编译时错误检查
示例:
typescript
// ✅ 类型安全
editor.chain()
.focus()
.setHeading({ level: 1 }) // level 必须是 1-6
.run()
// ❌ 编译错误
editor.chain()
.focus()
.setHeading({ level: 7 }) // 错误:level 超出范围
.run()
2.2 与其他编辑器的对比
对比表格
| 特性 | Tiptap | Draft.js | Slate | Quill | TinyMCE |
|---|---|---|---|---|---|
| 框架支持 | React, Vue, Angular, Svelte | 仅 React | 仅 React | 框架无关 | 框架无关 |
| 无头设计 | ✅ | ✅ | ✅ | ❌ | ❌ |
| TypeScript | ✅ 完整 | ⚠️ 部分 | ✅ 完整 | ⚠️ 部分 | ⚠️ 部分 |
| 协同编辑 | ✅ 内置 | ❌ 需自行实现 | ⚠️ 需插件 | ❌ 需自行实现 | ✅ 付费 |
| 扩展系统 | ✅ 强大 | ⚠️ 一般 | ✅ 强大 | ⚠️ 一般 | ✅ 强大 |
| 学习曲线 | ⚠️ 中等 | ⚠️ 陡峭 | ⚠️ 陡峭 | ✅ 平缓 | ✅ 平缓 |
| 包体积 | ⚠️ 中等 (45KB) | ⚠️ 大 (100KB+) | ⚠️ 中等 (50KB) | ✅ 小 (43KB) | ❌ 很大 (500KB+) |
| 性能 | ✅ 优秀 | ⚠️ 一般 | ✅ 优秀 | ✅ 优秀 | ⚠️ 一般 |
| 社区活跃度 | ✅ 非常活跃 | ⚠️ 维护模式 | ✅ 活跃 | ⚠️ 一般 | ✅ 活跃 |
| 商业支持 | ✅ 有 | ❌ 无 | ❌ 无 | ❌ 无 | ✅ 有 |
| 开源协议 | MIT | MIT | MIT | BSD | GPL/商业 |
详细对比
1. Tiptap vs Draft.js
typescript
// Draft.js(仅 React,API 复杂)
const [editorState, setEditorState] = useState(
EditorState.createEmpty()
)
const handleBold = () => {
setEditorState(
RichUtils.toggleInlineStyle(editorState, 'BOLD')
)
}
// Tiptap(多框架,API 简洁)
const editor = useEditor({
extensions: [StarterKit],
})
const handleBold = () => {
editor.chain().focus().toggleBold().run()
}
优势:
- ✅ 更简洁的 API
- ✅ 支持多框架
- ✅ 内置协同编辑
- ✅ 更好的 TypeScript 支持
2. Tiptap vs Slate
typescript
// Slate(需要更多样板代码)
const [editor] = useState(() => withReact(createEditor()))
const handleBold = () => {
const isActive = isMarkActive(editor, 'bold')
if (isActive) {
Editor.removeMark(editor, 'bold')
} else {
Editor.addMark(editor, 'bold', true)
}
}
// Tiptap(更高级的抽象)
const editor = useEditor({
extensions: [StarterKit],
})
const handleBold = () => {
editor.chain().focus().toggleBold().run()
}
优势:
- ✅ 更高级的抽象
- ✅ 开箱即用的扩展
- ✅ 更好的文档
- ✅ 内置协同编辑
3. Tiptap vs Quill
javascript
// Quill(有预设 UI)
const quill = new Quill('#editor', {
theme: 'snow', // 必须使用预设主题
modules: {
toolbar: [['bold', 'italic']] // 预设工具栏
}
})
// Tiptap(无头设计)
const editor = new Editor({
element: document.querySelector('#editor'),
extensions: [StarterKit],
})
// 自定义工具栏(完全自由)
<button onClick={() => editor.chain().focus().toggleBold().run()}>
Bold
</button>
优势:
- ✅ 完全自定义 UI
- ✅ 更强大的扩展系统
- ✅ 更好的 TypeScript 支持
- ✅ 内置协同编辑
4. Tiptap vs TinyMCE
javascript
// TinyMCE(传统编辑器,包体积大)
tinymce.init({
selector: '#editor',
plugins: 'lists link image', // 需要配置插件
toolbar: 'bold italic | bullist numlist',
// 500KB+ 的包体积
})
// Tiptap(现代编辑器,按需加载)
const editor = new Editor({
element: document.querySelector('#editor'),
extensions: [
StarterKit, // 只加载需要的扩展
],
// ~45KB 的核心包
})
优势:
- ✅ 更小的包体积
- ✅ 按需加载
- ✅ 现代化的 API
- ✅ 开源且免费
2.3 选择 Tiptap 的场景
✅ 适合使用 Tiptap 的场景
1. 需要自定义 UI 的项目
- 有自己的设计系统
- 需要与现有 UI 库集成
- 需要独特的用户体验
2. 协同编辑应用
- 团队文档协作
- 实时笔记应用
- 多人编辑平台
3. 现代前端项目
- 使用 React、Vue、Angular 等框架
- 需要 TypeScript 支持
- 追求高性能
4. 需要高度定制的编辑器
- 特殊的内容类型(如代码、数学公式)
- 自定义的编辑行为
- 复杂的业务逻辑
5. 长期维护的项目
- 需要稳定的技术栈
- 需要活跃的社区支持
- 需要持续的更新
❌ 不适合使用 Tiptap 的场景
1. 快速原型开发
- 需要立即可用的编辑器
- 没有时间自定义 UI
- 推荐:Quill、TinyMCE
2. 简单的文本编辑需求
- 只需要基础的格式化
- 不需要复杂功能
- 推荐:
<textarea>+ Markdown
3. 不熟悉现代前端技术
- 不了解 React、Vue 等框架
- 不熟悉 npm/webpack
- 推荐:传统的 WYSIWYG 编辑器
4. 需要开箱即用的 UI
- 没有设计资源
- 需要预设的工具栏和菜单
- 推荐:TinyMCE、CKEditor
3. Tiptap 的核心特性
3.1 扩展系统
Tiptap 的一切都是扩展。
扩展类型
1. Nodes(节点)
块级内容,如段落、标题、图片。
typescript
import { Node } from '@tiptap/core'
const Paragraph = Node.create({
name: 'paragraph',
group: 'block',
content: 'inline*',
// ...
})
2. Marks(标记)
内联样式,如加粗、斜体、链接。
typescript
import { Mark } from '@tiptap/core'
const Bold = Mark.create({
name: 'bold',
parseHTML: () => [{ tag: 'strong' }],
renderHTML: () => ['strong', 0],
// ...
})
3. Extensions(功能扩展)
功能性扩展,如历史记录、占位符。
typescript
import { Extension } from '@tiptap/core'
const History = Extension.create({
name: 'history',
addCommands() {
return {
undo: () => ({ commands }) => commands.undo(),
redo: () => ({ commands }) => commands.redo(),
}
},
// ...
})
StarterKit
官方提供的扩展集合,包含最常用的 15+ 个扩展。
typescript
import StarterKit from '@tiptap/starter-kit'
const editor = new Editor({
extensions: [
StarterKit, // 一次性加载所有基础扩展
],
})
// StarterKit 包含:
// - Document, Paragraph, Text
// - Heading, Blockquote, CodeBlock
// - BulletList, OrderedList, ListItem
// - Bold, Italic, Strike, Code
// - HardBreak, HorizontalRule
// - History, Dropcursor, Gapcursor
3.2 Commands(命令系统)
Commands 是执行编辑器操作的方式。
基本用法
typescript
// 单个命令
editor.commands.toggleBold()
// 链式调用
editor.chain()
.focus()
.toggleBold()
.toggleItalic()
.run()
// 检查命令是否可用
if (editor.can().toggleBold()) {
editor.chain().focus().toggleBold().run()
}
常用命令
typescript
// 文本格式
editor.chain().focus().toggleBold().run()
editor.chain().focus().toggleItalic().run()
editor.chain().focus().toggleStrike().run()
// 标题
editor.chain().focus().setHeading({ level: 1 }).run()
editor.chain().focus().toggleHeading({ level: 2 }).run()
// 列表
editor.chain().focus().toggleBulletList().run()
editor.chain().focus().toggleOrderedList().run()
// 内容操作
editor.chain().focus().insertContent('Hello').run()
editor.chain().focus().setContent('<p>Hello</p>').run()
editor.commands.clearContent()
// 历史记录
editor.chain().focus().undo().run()
editor.chain().focus().redo().run()
3.3 Schema(文档模式)
Schema 定义了文档的结构和规则。
文档结构
scss
Document(文档)
├── Heading(标题)
│ └── Text(文本)
├── Paragraph(段落)
│ ├── Text(文本)
│ ├── Bold(加粗标记)
│ └── Link(链接标记)
└── Image(图片)
内容表达式
typescript
// Paragraph 可以包含任意内联内容
content: 'inline*'
// Heading 可以包含文本和标记
content: 'text*'
// Document 必须包含至少一个块级元素
content: 'block+'
3.4 协同编辑
基于 Y.js(CRDT)的实时协同编辑。
基本配置
typescript
import Collaboration from '@tiptap/extension-collaboration'
import CollaborationCursor from '@tiptap/extension-collaboration-cursor'
import * as Y from 'yjs'
import { WebsocketProvider } from 'y-websocket'
// 创建 Y.js 文档
const ydoc = new Y.Doc()
// 连接到协同服务器
const provider = new WebsocketProvider(
'ws://localhost:1234',
'document-name',
ydoc
)
// 配置编辑器
const editor = new Editor({
extensions: [
StarterKit.configure({
history: false, // 禁用本地历史记录
}),
Collaboration.configure({
document: ydoc,
}),
CollaborationCursor.configure({
provider,
user: {
name: 'John Doe',
color: '#f783ac',
},
}),
],
})
特性
- ✅ 实时同步
- ✅ 离线编辑
- ✅ 冲突自动解决
- ✅ 协作光标
- ✅ 用户状态
4. Tiptap 生态系统
4.1 官方包
less
@tiptap/core - 核心包
@tiptap/react - React 集成
@tiptap/vue-2 - Vue 2 集成
@tiptap/vue-3 - Vue 3 集成
@tiptap/starter-kit - 基础扩展集合
@tiptap/extension-* - 100+ 官方扩展
@tiptap/pm - ProseMirror 依赖
4.2 Pro 扩展(付费)
Tiptap 提供了一些高级的付费扩展:
- Emoji - 表情符号支持
- FileHandler - 文件拖放处理
- Mathematics - LaTeX 数学公式
- UniqueID - 节点唯一 ID
- TableOfContents - 目录生成
- Comments - 评论系统
定价:
- 个人开发者:$99/年
- 团队:$299/年
- 企业:联系销售
4.3 社区资源
- 官方文档 :tiptap.dev
- GitHub :github.com/ueberdosis/...
- Discord 社区:活跃的开发者社区
- 示例项目 :tiptap.dev/examples
- 扩展市场:社区贡献的扩展
5. 快速开始预览
让我们快速预览一下 Tiptap 的使用:
tsx
// 1. 安装
npm install @tiptap/react @tiptap/starter-kit
// 2. 创建编辑器
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
function Editor() {
const editor = useEditor({
extensions: [StarterKit],
content: '<p>Hello World! 🌍</p>',
})
return <EditorContent editor={editor} />
}
// 3. 添加工具栏
function Toolbar({ editor }) {
return (
<div>
<button onClick={() => editor.chain().focus().toggleBold().run()}>
Bold
</button>
<button onClick={() => editor.chain().focus().toggleItalic().run()}>
Italic
</button>
</div>
)
}
就是这么简单!在接下来的章节中,我们将深入学习每个部分。
6. 本章总结
在本章中,我们学习了:
✅ 核心概念
1. Tiptap 是什么
- 无头的富文本编辑器框架
- 基于 ProseMirror
- 框架无关
2. 核心理念
- 可扩展性
- 类型安全
- 声明式 API
- 协同优先
3. 核心优势
- 现代化的开发体验
- 完全自定义的 UI
- 丰富的扩展生态
- 强大的协同编辑
- 高性能
- 类型安全
📊 对比其他编辑器
| 编辑器 | 适用场景 |
|---|---|
| Tiptap | 需要自定义 UI、协同编辑、现代前端项目 |
| Draft.js | React 项目,但已进入维护模式 |
| Slate | React 项目,需要底层控制 |
| Quill | 快速原型,需要预设 UI |
| TinyMCE | 传统项目,需要开箱即用 |
🎯 适用场景
适合:
- 自定义 UI 需求
- 协同编辑应用
- 现代前端项目
- 高度定制需求
- 长期维护项目
不适合:
- 快速原型开发
- 简单文本编辑
- 不熟悉现代前端
- 需要开箱即用的 UI
🔑 关键特性
- 扩展系统:Nodes、Marks、Extensions
- Commands:链式调用、类型安全
- Schema:文档结构定义
- 协同编辑:基于 Y.js 的 CRDT
8. 扩展阅读
最后欢迎大家一起来学习 企业级前端AI和基建项目实战!
期待下一章节!欢迎评论区交流技术!