字节笔记本
2026年2月22日
Slate:完全可定制的 React 富文本编辑器框架
Slate 是一个完全可定制的富文本编辑器框架,让你能够构建类似 Medium、Dropbox Paper 或 Google Docs 的富文本编辑器,而无需让代码库陷入复杂性。它基于 React 构建,采用插件化架构,所有逻辑都通过一系列插件实现,因此你不会被"核心"功能所限制。
项目简介
Slate 由 Ian Storm Taylor 创建,是一个开源的富文本编辑器框架。截至目前,该项目在 GitHub 上已获得 31.5k+ stars,拥有 3.3k+ forks,是一个社区驱动的项目。Slate 的设计灵感来源于 Draft.js、Prosemirror 和 Quill 等编辑器库。
注意:Slate 目前处于 Beta 阶段,核心 API 已经可用,但在高级用例中可能需要提交 PR 来改进或修复一些 bug。部分 API 尚未"最终确定",可能会随着时间推移而有破坏性变更。
为什么选择 Slate?
在创建 Slate 之前,作者尝试了 Draft.js、Prosemirror、Quill 等富文本库。虽然简单的示例很容易实现,但一旦尝试构建类似 Medium、Dropbox Paper 或 Google Docs 的编辑器,就会遇到以下深层问题:
- 编辑器的"schema"被硬编码且难以定制 - 粗体和斜体开箱即用,但评论、嵌入或更特定领域的需求呢?
- 程序化转换文档非常繁琐 - 用户写入可能有效,但程序化更改对于构建高级行为至关重要,却 unnecessarily 复杂
- 序列化为 HTML、Markdown 等似乎是事后考虑 - 简单地将文档转换为 HTML 或 Markdown 涉及编写大量样板代码
- 重新发明视图层似乎效率低下且受限 - 大多数编辑器使用自己的视图,而不是使用 React 等现有技术
- 协同编辑没有预先设计 - 编辑器的内部数据表示通常使其无法用于实时协同编辑用例
- 代码库是单一的,而不是小而可重用的 - 许多编辑器的代码库没有公开可以重用的内部工具
- 构建复杂的嵌套文档是不可能的 - 许多编辑器围绕简单的"扁平"文档设计
核心设计原则
Slate 通过以下原则解决上述问题:
1. 一流的插件
插件是 Slate 最重要的部分。这意味着你可以完全自定义编辑体验,构建像 Medium 或 Dropbox 那样的复杂编辑器,而无需与库的假设作斗争。
2. 无 Schema 核心
Slate 的核心逻辑对你将编辑的数据 schema 假设很少,这意味着库中没有会绊倒你的假设。
3. 嵌套文档模型
Slate 使用的文档模型是嵌套的、递归的树,就像 DOM 本身一样。这意味着创建表格或嵌套引用等复杂组件对于高级用例是可能的。
4. 与 DOM 并行
Slate 的数据模型基于 DOM - 文档是嵌套树,使用选择和范围,并公开所有标准事件处理程序。这意味着表格或嵌套引用等高级行为是可能的。
5. 直观的命令
Slate 文档使用"命令"进行编辑,这些命令被设计为高级且极其直观,因此自定义功能尽可能具有表现力。
6. 支持协同编辑的数据模型
Slate 使用的数据模型 - 特别是操作如何应用于文档 - 已被设计为允许在顶部叠加协同编辑。
7. 清晰的"核心"边界
通过插件优先架构和无 schema 核心,"核心"和"自定义"之间的边界变得更加清晰。
技术栈
- React - 基于 React 构建的视图层
- TypeScript - 完全使用 TypeScript 编写
- Lerna - Monorepo 管理工具
- Yarn Workspaces - 包管理
安装指南
前置要求
- Node.js >= 18
- React >= 18
- TypeScript >= 5.2
安装核心包
# 使用 npm
npm install slate slate-react
# 或使用 yarn
yarn add slate slate-react
# 或使用 pnpm
pnpm add slate slate-react可选插件包
# 添加历史记录(撤销/重做)支持
npm install slate-history
# 添加 Hyperscript 工具(用于测试)
npm install slate-hyperscript快速开始
以下是一个最基本的 Slate 编辑器示例:
import React, { useState, useCallback } from 'react'
import { createEditor, Descendant } from 'slate'
import { Slate, Editable, withReact } from 'slate-react'
const App = () => {
const [editor] = useState(() => withReact(createEditor()))
const [value, setValue] = useState<Descendant[]>([
{
type: 'paragraph',
children: [{ text: 'Hello Slate!' }],
},
])
const renderElement = useCallback((props) => {
switch (props.element.type) {
case 'code':
return <CodeElement {...props} />
default:
return <DefaultElement {...props} />
}
}, [])
return (
<Slate editor={editor} initialValue={value} onChange={setValue}>
<Editable renderElement={renderElement} />
</Slate>
)
}
const CodeElement = (props) => {
return (
<pre {...props.attributes}>
<code>{props.children}</code>
</pre>
)
}
const DefaultElement = (props) => {
return <p {...props.attributes}>{props.children}</p>
}核心包介绍
Slate 的代码库是一个 Monorepo,包含以下核心包:
| 包名 | 描述 | 大小 |
|---|---|---|
slate | Slate 的核心数据模型逻辑 | ~20KB (gzip) |
slate-react | 用于渲染 Slate 编辑器的 React 组件 | ~40KB (gzip) |
slate-history | 添加撤销/重做历史记录的插件 | ~5KB (gzip) |
slate-hyperscript | 用于编写 JSX Slate 文档的 Hyperscript 工具 | ~5KB (gzip) |
slate-dom | DOM 相关工具函数 | ~10KB (gzip) |
使用示例
富文本编辑器
import { Editor, Transforms, Element as SlateElement } from 'slate'
// 切换粗体格式
const toggleBold = (editor) => {
const isActive = isBoldActive(editor)
Transforms.setNodes(
editor,
{ bold: isActive ? null : true },
{ match: (n) => Text.isText(n), split: true }
)
}自定义元素
// 定义一个引用块元素
const QuoteElement = ({ attributes, children }) => {
return (
<blockquote {...attributes} style={{ borderLeft: '2px solid #ddd', paddingLeft: '10px' }}>
{children}
</blockquote>
)
}处理键盘事件
const onKeyDown = (event) => {
if (event.key === '`' && event.ctrlKey) {
event.preventDefault()
// 切换代码块
toggleCodeBlock(editor)
}
}官方示例
Slate 提供了丰富的官方示例:
- Plain text - 最基本的用例:一个增强版的
<textarea> - Rich text - 基本编辑器功能
- Markdown preview - 添加 Markdown 快捷键
- Inlines - 使用内联节点包装文本
- Images - 使用 void(无文本)节点添加图片
- Hovering toolbar - 悬浮工具栏实现
- Tables - 嵌套块渲染表格
- Paste HTML - 使用 HTML 序列化处理粘贴的 HTML
- Mentions - 使用内联 void 节点实现 @提及功能
学习资源
中文文档
注意事项
- Beta 阶段 - API 可能会有破坏性变更,生产环境使用前请仔细评估
- 社区驱动 - 没有大公司支持,所有贡献都是自愿的
- 需要 React 知识 - 基于 React 构建,需要一定的 React 基础
- 学习曲线 - 相比简单的富文本编辑器,Slate 的学习曲线较陡,但灵活性更高
相关项目
- flomo-editor - 基于 React + Slate.js 的开源富文本编辑器
许可证
Slate 使用 MIT 许可证 开源。