☰
BlockSuite 预设完全上手指南:5 行代码集成 PageEditor 和 EdgelessEditor
2026/9/26 2:59:03 网站建设 项目流程

BlockSuite 预设完全上手指南:5 行代码集成 PageEditor 和 EdgelessEditor

【免费下载链接】blocksuite🧩 Content editing tech stack for the web - BlockSuite is a toolkit for building editors and collaborative applications.项目地址: https://gitcode.com/GitHub_Trending/bl/blocksuite

假设你要做一个"既能写文档、又能开白板"的协作产品,从零造轮子至少要做块模型、选区、渲染管线和同步协议。BlockSuite 预设把这部分打包好了:装一个@blocksuite/presets,建一个 Doc,5 行代码挂上编辑器,Notion 式的 PageEditor 和无限画布的 EdgelessEditor 都能直接跑,而且两者共用同一份数据,切换视图不丢内容。

🧩 一个心智模型:两个编辑器只是"同一棵块树的两种渲染"

先抓住一个类比:文档是一棵块树,编辑器只是渲染这棵树的一种方式。

BlockSuite 里的 Doc 是一棵树:根节点是affine:page,下面挂着画布(affine:surface)和笔记块(affine:note),笔记块里再挂段落、列表、表格。PageEditor 把这棵树从上到下渲染成纵向滚动的页面;EdgelessEditor 把同一棵树渲染成自由拖动的卡片,铺在无限画布上。数据一模一样,区别只在"用哪套根块和视图来画"。

图中间就是两边共用的块树。理解了这张图,预设部分只剩两个名词:

  • BlockSpec:一个块的"完整包",包含数据结构(Schema)、视图组件(View)、业务逻辑(Service)三层,再加斜杠菜单、工具条这类可选挂件。
  • Specs 列表:一个编辑器到底启用哪些块,就是一个数组。PageEditor 用PageEditorBlockSpecs,EdgelessEditor 用EdgelessEditorBlockSpecs,两份列表的差异就是"两种编辑器"的全部秘密。

先盘家底:7 类预设组件各管什么事

预设包(presets 源码)导出的东西不多,但每样都有明确分工:

组件你能拿到什么
PageEditor纵向文档编辑:直接打字,/唤起块菜单,标题、多级列表、代码、表格都在
EdgelessEditor无限画布:缩放、平移、自由拖动笔记块,带画框(frame)和画布自由文本
AffineEditorContainer页面/白板一键切换的容器,自带文档标题和标签区,省去自己拼 TopBar 的活
Outline跟随块树实时生成的侧边大纲,点击标题跳到对应块
doc-title / comment / frame-panel标题、行内评论、画布画框管理,都是可直接插入的独立组件
AI 聊天块预置的聊天消息列表组件,接上自己的模型输出就是 AI 对话界面
createEmptyDoc()一次调用拿到带 page + 画布 + 笔记 + 段落的空文档,本地演示不用手写初始化

两种编辑器内置的块阵容相同:段落、列表、代码、数据库表格、数据视图、分割线、图片、附件、书签,外加 Figma、GitHub、YouTube、Loom、HTML、关联文档、同步文档 7 种嵌入块。区别只在根块和画布块用的是哪份 Spec。

🚀 5 行代码跑起来一个能用的编辑器

一条主线走到底:装依赖 → 建文档 → 挂载。

第一步,装三个包(presets 是成品编辑器,blocks 提供块定义,store 是数据层):

pnpm add @blocksuite/presets @blocksuite/blocks @blocksuite/store

第二步,在新页面的入口文件里写这 5 行:

import '@blocksuite/presets/themes/affine.css'; import { createEmptyDoc, AffineEditorContainer } from '@blocksuite/presets'; const { doc, init } = createEmptyDoc(); init(); const editor = new AffineEditorContainer(); editor.doc = doc; document.body.append(editor);

刷新页面就能打字,/出斜杠菜单,标题、列表、表格随手插。想把视图换成白板,把导入和实例化换成EdgelessEditor即可;两个视图都要且数据互通,就保持用AffineEditorContainer,调editor.switchEditor('edgeless')切换。

不满足于最小片段的话,仓库里 examples 目录 有 React、Vue、Angular、Preact、Svelte、Solid 共 11 个可直接运行的示例,覆盖 IndexedDB、SQLite 本地持久化和 WebSocket 实时同步,照着改比从零搭快得多。

为什么拆成"Specs + 编辑器"两层

这个拆分背后是三个明确的设计取舍:

取舍一:功能集用数组声明,而不是写死在组件里。因为"启用哪些块"只是一个列表,同一份 Doc 就能派生出页面版、白板版和只读预览版(preview规格列表)三套渲染。切换视图等于换数组,数据零迁移——这就是上一节那张图能成立的原因。

取舍二:编辑器本体只是薄壳。三种编辑器组件都是 Web Component(浏览器原生自定义元素,不绑定任何前端框架),所以丢进 React、Vue 或纯 HTML 的接法完全相同。想深度定制某个块的长相时,做法不是改编辑器,而是写一份自己的 BlockSpec 塞进数组里,规格清单在 blocks 的 specs 目录 里能看到每种块的结构。

取舍三:数据层天生为协作准备。Doc 底层基于 Yjs(CRDT,一种允许双方同时写、自动合并冲突的数据结构),所以"多人实时编辑"不是后期加的功能,而是换一个数据提供器(provider)的事。examples 里 IndexedDB、SQLite、WebSocket 三种接法都有现成代码。

选页面、选白板还是一键切换,附 4 个坑

选型看产品形态:

你的产品选择原因
纯长文写作、知识库PageEditor纵向滚动心智最顺,焦点管理现成
白板、脑暴、无限画布EdgelessEditor缩放平移、自由定位、画框都是内置行为
AFFiNE 式"文档 + 白板"二合一AffineEditorContainer一份 Doc 切两个视图,标题标签区附带

实战里容易踩的 4 个坑:

  1. SSR 会直接抛错。@blocksuite/presets在 Node 环境 import 会主动报错,同构框架(Next.js 等)记得把编辑器做成客户端懒加载。
  2. 只能 import 一次。同一页面里重复引入 presets 会破坏单例检查,控制台会给出明确告警,出现时优先查打包配置。
  3. 别漏主题 CSS。第一行的themes/affine.css不是装饰,不导入就是无样式裸组件。
  4. Doc 没有 root 时编辑器渲染空白。render逻辑里doc.root为空就不输出任何内容,所以必须先addBlock或doc.load()完成再挂载,顺序反了看到的就是白屏。

另外注意:页面模式下没有画框和自由文本,笔记块在白板模式下会渲染成可拖动卡片——这不是 bug,正是两份 Specs 列表的差异所在。

下一步:git clone https://gitcode.com/GitHub_Trending/bl/blocksuite,进 examples 目录跑一个你熟悉的框架,再对照 quick-start 指南 把createEmptyDoc()换成你自己的数据源,一个属于你自己的编辑器就成形了。

【免费下载链接】blocksuite🧩 Content editing tech stack for the web - BlockSuite is a toolkit for building editors and collaborative applications.项目地址: https://gitcode.com/GitHub_Trending/bl/blocksuite

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询