ByteNoteByteNote

字节笔记本

2026年2月21日

Slate:完全可定制的 React 富文本编辑器框架

API中转
¥120

Slate 是一个完全可定制的富文本编辑器框架,让你能够构建类似 Medium、Dropbox Paper 或 Google Docs 的富文本编辑器,而无需让代码库陷入复杂性。它基于 React 构建,采用插件化架构,所有逻辑都通过一系列插件实现,因此你不会被"核心"功能所限制。

项目简介

Slate 由 Ian Storm Taylor 创建,是一个开源的富文本编辑器框架。截至目前,该项目在 GitHub 上已获得 31.5k+ stars,拥有 3.3k+ forks,主要使用 TypeScript (87.9%) 和 JavaScript (11.4%) 编写,被超过 27 万个项目使用。

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. 一流的插件 API

Slate 的核心逻辑都是插件。你可以完全定制编辑体验的各个方面,没有什么是被"核心"预设的。

2. 无 Schema 限制

Slate 的文档模型比大多数编辑器更开放,允许嵌套文档结构,而不需要处理异常或边缘情况。

3. 嵌套文档模型

Slate 的文档模型允许任意嵌套,可以创建复杂的富文本文档,如表格中的表格、引用块中的列表等。

4. 与 React 集成

Slate 直接构建在 React 之上,使用 React 的渲染机制,不需要学习新的视图层或模板语言。

5. 不可变数据

Slate 使用不可变数据结构,使得协同编辑、撤销/重做等功能更容易实现。

6. 核心包小巧

Slate 的核心包非常小,只包含必要的功能,其他功能通过插件添加。

7. 支持协同编辑

Slate 的数据模型从一开始就考虑了协同编辑的需求,支持 Operational Transformation 等算法。

技术栈

  • TypeScript (87.9%) - 主要开发语言,提供类型安全
  • React - 视图层框架
  • Lerna - Monorepo 管理工具
  • Yarn Workspaces - 包管理

安装指南

Slate 是一个 monorepo,分为多个 npm 包,安装方式如下:

bash
# 使用 yarn
yarn add slate slate-react

# 或使用 npm
npm install slate slate-react

# 或使用 pnpm
pnpm add slate slate-react

同时需要安装 peer dependencies:

bash
yarn add react react-dom

快速开始

以下是一个最基本的 Slate 编辑器示例:

jsx
import React, { useState } from 'react'
import { createEditor } from 'slate'
import { Slate, Editable, withReact } from 'slate-react'

const App = () => {
  // 创建一个 Slate 编辑器对象,在渲染之间保持稳定
  const [editor] = useState(() => withReact(createEditor()))

  // 初始文档内容
  const initialValue = [
    {
      type: 'paragraph',
      children: [{ text: 'A line of text in a paragraph.' }],
    },
  ]

  return (
    <Slate editor={editor} initialValue={initialValue}>
      <Editable />
    </Slate>
  )
}

export default App

TypeScript 类型定义

如果使用 TypeScript,需要添加类型声明:

typescript
import { BaseEditor, Descendant } from 'slate'
import { ReactEditor } from 'slate-react'

type CustomElement = { type: 'paragraph'; children: CustomText[] }
type CustomText = { text: string }

declare module 'slate' {
  interface CustomTypes {
    Editor: BaseEditor & ReactEditor
    Element: CustomElement
    Text: CustomText
  }
}

使用示例

添加事件处理

jsx
import React, { useState } from 'react'
import { createEditor } from 'slate'
import { Slate, Editable, withReact } from 'slate-react'

const App = () => {
  const [editor] = useState(() => withReact(createEditor()))
  const [value, setValue] = useState([
    {
      type: 'paragraph',
      children: [{ text: 'A line of text in a paragraph.' }],
    },
  ])

  return (
    <Slate editor={editor} initialValue={value} onChange={setValue}>
      <Editable
        onKeyDown={event => {
          if (event.key === '&') {
            event.preventDefault()
            editor.insertText('and')
          }
        }}
      />
    </Slate>
  )
}

自定义渲染

jsx
const renderElement = props => {
  switch (props.element.type) {
    case 'code':
      return <pre {...props.attributes}>{props.children}</pre>
    default:
      return <p {...props.attributes}>{props.children}</p>
  }
}

const renderLeaf = props => {
  return (
    <span
      {...props.attributes}
      style={{ fontWeight: props.leaf.bold ? 'bold' : 'normal' }}
    >
      {props.children}
    </span>
  )
}

// 在 Editable 组件中使用
<Editable renderElement={renderElement} renderLeaf={renderLeaf} />

包结构

Slate 的代码库是 monorepo,由以下包组成:

包名描述是否必需
slateSlate 编辑器的核心逻辑
slate-reactReact 视图层组件是(如果使用 React)
slate-history撤销/重做历史记录插件
slate-hyperscript用于创建 Slate 文档的 Hyperscript 工具否(测试用)

官方示例

Slate 提供了丰富的示例,展示各种使用场景:

  • Plain text - 纯文本编辑器
  • Rich text - 富文本编辑器(粗体、斜体等)
  • Markdown preview - Markdown 实时预览
  • Links - 链接处理
  • Images - 图片嵌入
  • Tables - 表格编辑
  • Mentions - @提及功能
  • Embeds - 嵌入第三方内容
  • Forced layout - 强制布局
  • Hovering toolbar - 悬浮工具栏
  • Collaborative editing - 协同编辑

所有示例都可以在 slatejs.org 查看源代码。

相关项目

基于 Slate 构建的开源项目:

  • Plate - 高级 Slate 插件集合
  • Slate Plugins - Slate 插件库
  • Remirror - 基于 ProseMirror 和 Slate 的编辑器框架
  • flomo-editor - 基于 React + Slate.js 的开源富文本编辑器

项目链接

许可证

Slate 使用 MIT 许可证开源。

分享: