跳到正文
W Winse Blog
editor dev 1 min read

富文本编辑器开发学习笔记: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 方去绘制该元素。


通过插件机制:

  • 元素:解决单点扩展(表情、特殊字符)

  • 功能块:构建结构化块(列表)

让编辑器既能保持简洁,又能不断适应复杂场景的扩展。

在 GitHub 上讨论

欢迎通过 GitHub Issue 留言或反馈。每条讨论都会关联到对应文章的源文件路径。

2025-08-27-富文本编辑器开发学习笔记:Carota插件.md

Related posts