Article
富文本编辑器开发学习笔记:Carota插件
最初的富文本编辑器,只需满足基础功能:输入文字、简单排版、加粗变色。
但随着用户需求不断演变,编辑器的边界被逐渐的打破:
-
从单一到多样:不仅能写字,还得插入图片、表格、链接;
-
从简单到复杂:需要支持标题层级、脚注、上下标;
-
从个人到协作:要求撤销/重做、格式保持、多人协同编辑。
这些诉求已超出“能写字”的范畴。编辑器若要进阶,插件机制 就成为了必然。
Carota 作为基于 Canvas 的富文本编辑器,通过插件:
-
功能可按需扩展,保持核心精炼;
-
模块之间隔离,降低复杂度;
-
用户自由选择,体验灵活轻量的体验。
插件不只是附加,而是编辑器发展中的的必经之路。
元素插件:插入表情
该类插件用于扩展单一可视化元素,不改变文档整体结构,通常作为内联节点的形式存在。

插件注册和交互事件
插件需要注册自身,并响应相关的交互事件。

排版
1、characters(字素): 数据JSON对象作为一个整体,在字符索引中代表1个位置。

2、split(拆分为Word): 将它看做普通的内联文字,与前后文字连成一个word,双击就会一起被选中。功能块才有block和eof时进行了截断,下面在讲。

建立 Word ,在计算每个 Run 对应的 Box 时,会调用插件的 measure 方法,得到元素的宽度和高度。

3、wrap(构建文档树): 看作为一个内联字符,已经加到word里面了,无需额外特殊处理。
渲染
在渲染阶段,Box会调用插件中实现的 draw 方法绘制该元素,从而实现与文本内容的融合显示。

功能块插件:列表
这类插件往往由多个元素组成的块,需要修改段落与文档树层级结构,需要和渲染逻辑深度的结合。
阅读代码方法:看不懂的代码,先问问AI,代码的作用。从一个角度切入,有个引子,在这个基础上继续理解就比较容易了。

不必急着研究复杂的代码,先通过 输入和输出效果 建立直观的印象,再顺藤摸瓜地去追踪其代码实现。

可以看到在Carota中,Run 中 text 字段为一个JSON对象,键包括listStart、listNext、listEnd,分别对应列表的开始、项目和结束。
每个键都对应到一个 ICustomCode 插件。

插件注册与交互事件
列表插件是内置在内核代码中。功能还比较原始,还没有交互的逻辑。
排版
1、characters(字素):依然是作为一个整体,用一个1字符来表示。
2、split(拆分为Word):与元素插件相同,但 listStart 插件中定义了block,同时 listNext 和 listEnd 的 eof 标记为true,因此list的元字符都会断字、断行。

3、wrap(构建文档树): 每一个列表项由一个 frame 来承载,前缀数字则作为 marker。

每项的内容整体给到frame来建立层次文档树。
形成的结构为:
list
列表排版结束后返回list元素,并将其添加到外部的frame中。

排版排好后的文档树如下:

渲染
渲染阶段,与元素插件一样,Box调用插件中实现的 draw 方去绘制该元素。
通过插件机制:
-
元素:解决单点扩展(表情、特殊字符)
-
功能块:构建结构化块(列表)
让编辑器既能保持简洁,又能不断适应复杂场景的扩展。
Related
Related posts
-
从使用者到创造者:用 AI 构建你的专属 VS Code 工具链
2026-02-27
-
深入剖析Carota源码:从问题出发
2025-09-25
-
富文本编辑器开发学习笔记:跟踪canvas-editor有感,是金子终会发光
2025-09-07
-
深入解析 Nano Banana:Google 技术博客四篇精华翻译
2025-08-30