最近半年,我几乎逢人就安利一个叫 Univer 的开源项目。它不是一个简单的表格组件,而是一整套面向在线文档场景的基础设施。你要在 Web 端做出和 Excel 一样能打的表格,要支持公式、样式、协同,还要能被自己的团队继续扩展,Univer 是目前少有的开源答案。
这篇文章不是官方文档的搬运,而是我把 Univer 集成进生产项目之后的一次完整复盘。里面会聊到它的架构思路、落地步骤、性能调优,以及我在真实业务里踩过的坑。如果你正在评估自建在线表格、协作编辑或数据录入系统,这篇文章应该能帮你节省至少一周的试错时间。
1. 为什么是 Univer:一张能打的在线表格不是玄学
1.1 表格组件的旧世界与尴尬
在做 Univer 之前,我团队手里的“在线表格方案”其实是一堆代码拼出来的缝合怪。前端表格部分用过 Luckysheet,后来又试用过 Handsontable 和 ag-Grid,文件读写这边单独接了 SheetJS,公式计算则完全交给了后端。这套组合表面能用,但每次加需求都让人头皮发麻:表格组件只负责“显示”,不负责“计算”,更不负责“协同”。用户在界面上改了数据,前端要同步给后端,后端算完再回传刷新,一来一回几百毫秒,体验和真正的 Excel 差得远。
第一层尴尬在于,市面上很多组件其实叫“数据网格”更准确。它们擅长展示成千上万行结构化数据,做排序、筛选、翻页,但你要在某个单元格里手写一个带参数的 SUMIFS 公式,或者把几个单元格合并后再套一层条件格式,它就直接躺平了。第二层尴尬在于,Excel 的交互细节远比比想象的复杂:拖拽填充、下拉菜单、跨表引用、图表联动、撤销重做,这些功能看起来不起眼,真正自己做一遍才知道工作量有多大。
所以当团队决定把完整 Excel 编辑能力搬到 Web 上时,我们很快就意识到,采购商业控件是一条路,基于开源引擎二次开发是另一条路。前者授权费用不低,且定制空间有限;后者看似费时,但能掌握全部源码和路线图。Univer 正是在这个时间点进入视野。
1.2 Univer 到底是什么
用一句话概括,Univer 是面向开发者的“文档基础设施”,目前覆盖在线表格、在线文档和幻灯片三块能力,其中表格是它最成熟、社区关注度最高的部分。它的定位不是“又一个 JavaScript 表格库”,而是一个可以承载整个办公产品形态的引擎。
从技术视角看,Univer 有这样几个鲜明特征:
纯前端完成核心计算与渲染。表格的网格、文本、边框、填充色全部由 Canvas 绘制,不再依赖 DOM 生成一堆 div,因此数据量大时依然能保持可用的滚动流畅度。这一点在万行级数据场景下优势特别明显。
模块化插件体系。官方把核心、渲染、UI、公式、协同等拆成了不同 package,你可以只引入自己需要的部分。这为按需加载和深度定制留了非常充分的空间。
强大的公式引擎。Univer 在表格引擎内部实现了公式解析与计算,支持常见的 Excel 函数,也允许注册自定义函数。这意味着公式计算可以实时发生在浏览器端,而不是每次都要向后端请求。
协同编辑能力向开源靠拢。在线协同是当前很多团队选择 Univer 的核心原因之一。它支持类似 CRDT 的数据同步思路,让多人同时编辑一张表成为可能,这在开源表格方案里非常稀缺。
跨端渲染方案。除了 Web,它也能被集成进基于 Electron 的桌面客户端,移动端适配也已经有了官方探索。一套逻辑,多处复用。
正因如此,Univer 在线办公的形态,现在已经可以直接部署到企业内部系统里,做成“私有化在线 Excel”。相比使用商业云表格服务,自己掌控数据和源码的吸引力是巨大的。
1.3 什么场景适合用 Univer
我把它推荐给三类人。第一类是 ToB 系统开发团队,尤其是 ERP、CRM、财务、制造业台账这类“用户天天要在浏览器里整齐地录数、算数、导数”的场景。这类系统如果只给一个原生表格输入,交互很弱;如果重构成在线 Excel,用户上手完全无门槛。
第二类是正在自建协同办公平台的产品团队。如果你已经有文档系统、IM 或项目协作工具,下一步自然要做表格模块,那么直接接 Univer 的表格引擎,比自己从零做一套“类 Excel”要省太多时间。它天生就是一个开放平台,你可以在上面继续做进销存模板、项目管理模板、费用报销模板,等于把 Excel 的形与神都搬进了自己的产品。
第三类是对数据权限和编辑体验要求高的金融、法律、政府类项目。数据不能直接放在第三方公开服务器上,他们更愿意接受本地化部署。Univer 开源版没有云端依赖,只要前端能跑就能工作,数据全在本地服务上,安全性和可控性都有保证。
但这里也要泼一盆冷水:如果你的需求只是“在一个页面里展示一张 100 行的信息表格”,用 Univer 是杀鸡用牛刀。它整体的初始化和包体都更偏向“完整工作簿”场景,轻量需求选普通表格组件反而更简单。选型从来不是选最强的,而是选最合适的。
2. 拆解 Univer 的核心架构与设计思路
2.1 两条主线:渲染引擎与核心模型
我在接入 Univer 之前,先花了大概两周时间阅读它的源码结构。读懂 Univer 的关键,在于抓住两条主线:一条是数据模型的“逻辑主线”,另一条是渲染引擎的“视觉主线”。
数据模型这一侧,Univer 把工作簿、工作表、单元格、样式、行高列宽、合并信息全部组织成结构化数据。它不是你想象中的二维数组这么简单,而是一套带索引、带版本、带操作记录的数据结构。单元格的值不只是 value,还包括 formula、styleId、richText 等字段。所有变更都会经过 Command 管道,这意味着你写入的每一步操作都可被追踪、撤销、重新执行。
渲染引擎这一侧,Univer 使用了 Canvas 绘制。整个表格区域在页面上只是一个 canvas 节点,引擎通过虚拟化策略,只绘制当前视口内可见的单元格。用户拖动滚动条时,引擎不断重算可见区域,然后重绘对应网格。相比每个单元格都创建一个 DOM 元素的方案,这种方式的渲染压力要小一个量级。实际效果是,我一次渲染了 5 万行数据,交互依然能保持流畅,快速滚动的掉帧也远比之前用 DOM 方案克制。
这两条主线通过事件总线、命令机制和插件系统连接起来:用户在 UI 层拖动选区,UI 派发交互命令,命令去修改数据模型,数据模型变化触发渲染引擎局部更新。这套机制最大的好处是清晰,UI 层不会直接操作 DOM 里的表格节点,所有状态都归于模型。
2.2 命令模式与插件化:核心不膨胀的秘密
Univer 的插件体系值得单独拿出来聊,因为它决定了你能在上面扩展多少业务能力。
在 Univer 里,绝大多数用户操作都会被包装成 Command,比如“设置单元格值”“插入一行”“修改样式”“执行公式”。这些命令进入统一的调度系统后,会执行前置条件校验、模型更新、历史记录写入、渲染通知。通过命令层,Univer 保证了业务逻辑的统一性。你甚至可以在控制台主动派发命令来完成外部控制的表格修改,而不必去动内部对象。
插件体系则负责给核心“上装备”。官方插件包括 UI 组件、公式引擎、协同服务、导入导出、条件格式、筛选、数据透视表等。第三方开发者也可以注册自己的插件,比如自定义一种“审批单元格”或者说一个钩子,在某列数据变化时自动触发生成日志。我不需要 fork 主仓库改源码,只需要按照插件接口写一段代码,然后注册进去。这就让团队内部的业务定制变得非常干净:核心保持稳定,业务逻辑全部外置。
我之前遇到过很多开源项目,核心一升级,本地改过的源码就冲突成一片。Univer 的命令与插件机制基本消灭了这类问题。升级版本时,更多是检查插件 API 是否有 breaking change,而不是逐行解决 git 冲突。
2.3 协同背后的数据同步逻辑
如果只是单人编辑,Univer 的架构已经足够好用。但真正让项目复杂度上升的,是多人同时编辑同一张表。
我对协同的理解,经历了从“同步整张表”到“同步操作命令”的过程。最早想到的方案是“每隔几百毫秒把整个工作簿数据传给其他人”,听起来简单,但一旦数据量上来,网络带宽和合并冲突就会把方案压垮。Univer 的协同思路更像“同步操作”和“同步状态”的结合:每个人都拥有同一份文档状态的副本,操作以少数可识别的命令形式广播,另一端收到后,在本地应用同一套命令,从而让各方状态保持一致。
为了让并发修改不产生明显的冲突,协同模块还要处理操作合并。比如一个人正在修改 A 列,另一个人在修改 B 列,两者并发到达时应当互不干扰;如果两人同时修改了同一个单元格,则需要有规则来决定谁先谁后,或者保留合并后的可见历史。Univer 在这部分提供了插件级的协同接口,团队可以基于它接入自己的同步通道。
需要强调的是,协同对网络环境的稳定性要求很高。我的产线经历是:局域网内协同非常顺滑;一旦放到公网,丢包和延迟就会放大冲突解决的复杂度,这就要求前端做好状态回放、连接状态提示和操作重放。不要指望一个“能打字”的协同就足够,真正的协同还要解决离线编辑、断线重连、服务端鉴权等一连串问题。
3. 实操:把 Univer 拉进你的项目
3.1 环境准备与依赖安装
Univer 的开发环境要求不算苛刻,Node.js 16 以上即可,我自己是在 Node 18 环境下跑的。前端框架方面,Univer 是框架无关的,你可以在原生 JavaScript、React、Vue 里接入。它提供的是引擎级别的能力,外层 UI 可以使用官方预置,也可以自行定制。
安装核心依赖,最省事的方式是使用官方提供的 presets 包,它已经帮你组合了常用插件。用 pnpm 或 npm 安装都可以:
pnpm add @univerjs/presets如果希望手动控制引入模块,也可以拆开安装:
pnpm add @univerjs/core @univerjs/sheets @univerjs/sheets-ui @univerjs/ui @univerjs/engine-formula个人建议:项目刚起步时直接用 presets 快速跑通,等对模块有足够理解后再考虑按需拆包。原因是,Univer 的模块间依赖关系比较复杂,新手手工组合时很容易漏掉某个 styling 或 locale 包,导致界面异常。先跑通,再瘦身,这才是务实路径。
安装完成后,还需要准备一个撑满高度的容器元素。这一点看起来人畜无害,却是新手最常见的白屏元凶:因为 Univer 渲染容器高度为 0,Canvas 画出来自然什么都看不到。
3.2 创建并挂载工作簿
以一个最简单的初始化为例。HTML 里放一个 id 为 app 的 div,CSS 给它设置明确宽度和高度:
<div id="app" style="width: 100%; height: 600px;"></div>然后创建一个 Univer 实例。不同版本 API 会有差异,下面是基于我使用的 1.x 版本的示意写法:
import { Univer } from '@univerjs/core'; import { UniverPreset } from '@univerjs/presets'; const univer = new Univer({ // 全局配置,比如 locale、theme 等 locale: 'zhCN', }); univer.registerPlugin(UniverPreset, { // 该配置里开启表格、公式、UI 等需要的能力 });实际项目里,通常会把工作簿数据提取出来,放在初始化时交给引擎。比如后端返回一个工作簿 JSON,前端拿到后渲染到界面上。Univer 的数据结构比较规范,工作簿里可以包含多个工作表、单元格数据、合并单元格、行列配置、样式表等。初期不知道怎么写时,可以先用官方线上编辑器导出一个样例 JSON,再回头对照字段学习。
我踩过的一个坑是初始化时机。如果 Univer 在 DOM 尚未完全渲染时就开始挂载,很可能出现的表现是空白或者错位。稳妥做法是把初始化调用放进 useEffect 或 onMounted,并且确保容器已经拿到实际布局尺寸。
3.3 注入数据与基础样式
工作簿初始数据里最核心的是 sheetData 的 cellData。它看起来像是一个以行、列坐标作为键的映射结构。一个非常简单的例子:
const workbookData = { sheetData: { worksheet1: { cellData: { '0': { '0': { v: '销售额' }, '1': { v: 100 }, '2': { v: { f: 'SUM(B1:B3)' } } }, '1': { '0': { v: '费用' }, '1': { v: 30 } } } } } };字段的含义要弄清楚:v 表示单元格显示值或原始值,f 表示公式字符串,s 表示样式 id,p 表示富文本信息。单元格样式一般不在 cellData 里直接写 CSS,而是定义在 stylesList 中,通过 id 引用。这样多个单元格可以共享同一套样式,降低数据体积。
在真实业务里,我从后端拿到的大多是二维数组,转换成 Univer 的 cellData 需要写一个映射函数。建议把这段转换函数独立成工具模块,并在函数中处理空值、日期格式和公式前缀,避免把字符串'='误当成普通文本。
样式这块,初期建议直接看官方文档。我最常用的几个样式属性是背景色、加粗、边框、对齐方式、文本换行。条件格式是一套独立能力,同样通过插件或 API 配置,等基础样式跑通后再研究不迟。
3.4 开启公式与交互
公式能力是 Univer 区别于普通网格组件的分水岭。要在项目里用上公式,必须确保 Formula 相关的插件已经注册。如果只初始化了 Sheets 而没有注册 formula 插件,单元格里输入 '=SUM(A1:A10)',界面只会显示这个字符串,而不是计算结果。这个现象在初学时特别容易误判成“Univer 公式坏了”,其实是能力没开启。
公式注册之后,日常使用体验接近 Excel。输入等号,会自动弹出函数提示,支持参数占位;单元格引用跟着选区走,拖拽计算也不会出错。更重要的是,Univer 的公式计算在端内完成,不依赖网络请求,所以连续输入的体验没有卡顿。
如果你有业务私有函数,比如根据工单状态自动计算评分,可以通过注册自定义函数的方式加入。官方 API 可以拿到所有单元格数据作为参数,返回计算结果即可。这里要提醒一点:自定义函数的计算时机需要仔细设计,尽量设计成纯函数,不要在里面对 DOM 做操作,也不要依赖外部可变全局变量,否则一旦并发修改单元格,计算结果会变得不可预测。
4. 核心能力逐个实战:公式、导入导出、协同
4.1 公式引擎的边界与性能
实际使用后,我非常感慨公式引擎做在前端的价值。过去自研实现时,常常要同时维护前端一个计算结果,再给后端一个校验结果,两边的公式逻辑万一不一致,就会出现“界面显示的数字和导出出来的数字不一样”这种严重事故。Univer 把公式引擎统一放到前端,导出时同样由该引擎输出数据,基本避开了双重实现导致的不一致。
支持函数范围上,常见文本处理、统计、数学函数都做得很全。我们自己业务里大量使用 VLOOKUP、IF、SUMIFS、TEXT 这些日常函数,也都正常生效。数组公式在新版本里也得到支持,在做复杂表格时特别有用。
性能上需要注意:公式计算与单元格渲染是两套体系。如果一张表里写了上万条 VLOOKUP,首轮加载的计算时间可能会达到几秒。这个现象并不代表 Univer 卡死,只表明确实需要一些推理时间。优化手段是避免大范围公式的连锁依赖,尽量拆表;如果确实需要海量计算,可以先把静态数据预处理成结果,再在前端只保留必要的动态公式。
我自己的一个体验是:公式结果并不是即时显示的。在极端复杂的工作簿上,输入公式后会出现轻微延迟,这时不要反复按键,给它一点时间计算结果。若长时间不更新,就要检查是不是公式区域形成了循环引用,Univer 最终会给出错误提示,但排查路径最好从服务端日志和前端 console 两方面一起看。
4.2 导入导出 Excel:看起来简单,坑在细节
导入导出能力是“类 Excel”产品绕不开的环节。有人觉得只要会读 xlsx 文件就能搞定导入,真正接入后你会发现,难点集中在格式保真、大数据量内存控制、公式兼容这三件事上。
官方提供的导入导出插件支持 xlsx、csv 等格式。常规场景下,导入一个带合并单元格、批注、条件格式的 Excel 文件,Univer 能基本还原。但你要是拿一个用 VBA 宏做了大量动态逻辑的 Excel 文件过来,那就要有心理准备:宏必然是不支持的。Excel 里很多“看起来是静态值,其实是宏算出来的结果”,导进来后只会留下缓存值,不会再实时变化。这一点必须在需求评审时就跟甲方说清楚。
导出同样有坑。大文件导出时,前端的内存占用会瞬间飙升。我遇到过导出本身就是几十 MB 的 Excel,浏览器直接内存溢出崩溃的情况。后来加上了文件大小限制,超过阈值就引导用户走服务端导出通道。服务端同样用 Univer 的数据结构生成文件,或对接独立的开源库,能有效分担浏览器内存压力。
另外一个易踩的坑是富文本。Univer 单元格内支持富文本,比如同一格里的“订单号:123”中“123”要标红加粗。但导出到 xlsx 再导回来,富文本的样式可能会部分丢失。文件格式的兼容性,永远是办公软件绕过不掉的痛。所以我在项目里强调“导入导出做八分保真即可,核心数据必须无损;样式细节尽量保留,但不保证 100%”。
4.3 多人实时协同如何接入
协同是 Univer 的杀手锏,但也是最需要谨慎投入的部分。先说结论:它不像引入一个 npm 包那么简单,你还需要配套的同步服务与状态管理。
我理解的 Univer 协同链路是这样的:每个客户端维护同一份工作簿的本地状态;用户在界面上做任何修改,都会生成一个操作描述;这些操作被广播给协同服务端,服务端再转发给同一文档的其他客户端;各个客户端收到操作后应用到自己本地,同时更新版本信息。为了保证多端并发不互相踩踏,协同模块引入类似 CRDT 的冲突合并机制,让多个操作能够在不同顺序下最终收敛到一致状态。
实际落地时,最简单的方案是用官方提供的协同演示服务,把它跑通,证明“两个人同时编辑不丢字”。但生产环境不能照抄演示代码,你得自己做鉴权、会话管理、断线重连、历史记录、权限控制。比如这样一个场景:两个人同时修改同一行,一个删除了数据,另一个又输入了新值,最后以谁为准?默认 CRDT 会合并出一个状态,但产品上可能更希望按照业务规则走。这种规则需要在协同层之上再做一层业务拦截。
从我的经验看,协同功能最好按“渐进式增强”来推进。第一版只做单人编辑,保证核心表格能力稳定;第二版把协同打开,但先限制在局域网或小规模团队;第三版再优化公网体验、加入细粒度权限。一上来就挑战“百人同表”,很可能被各种网络场景折磨到怀疑人生。
5. 性能优化与常见问题排查实录
5.1 大数据量下的渲染性能
Univer 的 Canvas 渲染机制已经解决了一部分性能问题,但不代表可以不设防。5 万行纯文本数据、10 列结构简单,每行只有一个编号和几个状态字,这种情况下性能依然不错。但如果每行都有富文本、背景色、边框,还嵌套了多级合并单元格,渲染压力就会成倍上升。
我给团队定了几条硬性规范:第一,做低层渲染时,禁用频繁全量 setValue,使用批量更新接口或事件批量派发;第二,尽量少在表格里放图片。图片会触发独立的资源加载与绘制,大量图片单元格会明显卡顿;第三,单元格内的富文本,能压成纯文本就不要炫技,尤其不要在长列表里穿插大量彩色富文本。
如果遇到滚动时白块闪烁,先确认是否已将视口外单元格裁剪交给 Univer 默认策略。不要自己在渲染回调里反复查询不必要的数据。多数白块问题其实是因为主线程被业务脚本占满了,把表格渲染任务放到空闲时机,可以明显改善。
5.2 包体积与首屏优化
Univer 是一个能力很强的引擎,代价就是包体积不会太小。虽然模块化已经把它拆开了,但完整打开一个工作簿应用,gzip 后 1MB 到 2MB 是很正常的数字。如果项目对首屏性能极其敏感,需要做好代码拆分。
我实际采用的做法是,把 Univer 初始化和相关业务组件单独打成univer.js模块,通过动态 import 在用户真正打开表格页时才加载。表格页很少是系统首页,所以这个延迟对整体体验几乎没有影响。如果表格是核心主页面,还可以考虑预加载:用户登录后立刻在后台拉取脚本,等进入表格页时资源已经就绪。
如果你用 vite,务必开启代码分包,不要把所有包都塞进一个 chunk。Univer 自身的依赖关系很清晰,tree-shaking 效果一般情况下是及格的。我在生产配置里关闭了 sourcemap,并开启了 gzip,实际加载速度能从“明显卡顿”降到“感知轻微”。
5.3 高频问题与解决速查表
我汇总了一份团队内部高频问题表,这里分享出来:
| 问题现象 | 可能原因 | 解决思路 |
|---|---|---|
| 页面白屏 | 容器高度为 0 或初始化时机过早 | 给 div 设置高度,在 onMounted/useEffect 后初始化 |
| 单元格输入公式后不计算 | 未注册公式插件 | 检查 engine-formula 相关插件是否注册成功 |
| 滚轮滚动卡顿 | 每行富文本过多或图片过多 | 清理富文本样式,图片尺寸压到合理范围 |
| 导入 xlsx 后样式错乱 | 文件包含不兼容特性或宏内容 | 与上游确认文件规范,优先保存为标准格式 |
| 导出内存爆掉 | 文件过大,前端拼接所有数据 | 限制导出大小,切换服务端导出 |
| 表格初始化后工具栏缺失 | UI 插件未注册完整或主题未加载 | 检查完整插件列表,确认 locale 包已引入 |
| 协同编辑时偶发回退 | 网络丢包导致操作重放顺序异常 | 加固服务端消息顺序,前端增加重载恢复机制 |
这张表不能替代文档,但能帮新接手的人快速定位问题。排查时,我建议第一件事永远是打开浏览器 DevTools 看 console 报错。Univer 在自诊断方面的日志做得比较全,很多问题会在 console 里直接提示哪一行数据不合法。
5.4 从 Luckysheet 迁移到 Univer 的几只拦路虎
不少团队之前用的是 Luckysheet,现在想切换到 Univer。这个路径我熟,因为我自己就走过。最大的感觉是:Luckysheet 的 API 风格是“直接操作一堆配置对象”,而 Univer 更强调命令与插件。迁移不是把方法名替换一遍,而要重新梳理数据流。
第一个拦路虎是数据格式。Luckysheet 用 sheet 数据数组加各种celldata稀疏结构,Univer 则是标准工作簿 JSON。二者没有现成的无损转换器,需要对字段做映射。我当时写了一套转换工具,把 Luckysheet 的 v、ct、m、s 等字段映射成 Univer 的 v、f、s、p。纯文本和数字基本无损,但富文本和复杂样式会丢失一部分。
第二个拦路虎是脚本依赖。Luckysheet 时代很多自定义功能是通过修改源码或者全局注入实现的,迁到 Univer 后这些补丁全部失效。正确做法是把所有自定义逻辑统一收敛到插件和命令里。这需要投入额外工时,但从项目长期健康度看非常值得。改文档、形状或图表时的许多边界处理,都被 Univer 框架化了,业务代码反而更简洁。
第三个拦路虎是历史数据。已存在的 Luckysheet 文件如果需要向后兼容,要么保留旧的编辑器继续只读旧文件,要么做一次性数据迁移。我更推荐做明确的数据迁移,让所有新文档统一跑在 Univer 上,避免同时维护两套编辑器的巨大成本。
6. 一些实操心得与最后建议
6.1 什么时候别用 Univer
Univer 很强,但我也得客观说:它不适合所有“表格”需求。如果你只需要一个只读排行榜、信息统计表,或者数据网格式的运营后台,用 React/Vue 生态里的轻量表格组件会更快、更轻、更省心。Univer 的价值建立在“需要编辑、公式、协同”这些完整办公能力之上。
另外,如果你的产品需要完全离线的桌面端体验,而且团队已经绑定了 Excel COM 或宏生态,那也别硬换。Univer 是 Web 技术栈,桌面端需要借助 Electron 这类容器,和原生 Office 插件的集成能力不在一个维度。选型最忌讳看到新技术就强行上,适配需求永远排在追赶潮流前面。
团队技术栈也是考量因素。Univer 主要用 TypeScript 开发,插件接口比较面向 OOP。如果你的团队全部是纯函数风格的极简主义者,初期的上手曲线会更陡一些。不过只要把命令与插件讲清楚,多数人两周内就能进入稳定开发状态。
6.2 社区生态现状与源码阅读建议
Univer 的 GitHub 仓库活跃度在国产开源项目里算很不错的。官方文档和在线编辑器都维护得比较勤,遇到问题时,我建议先去搜 GitHub Issues,很多问题已经在讨论列表里出现过。交流群里有一线开发者在提问,也有一些核心贡献者答疑,整体氛围务实。
源码阅读方面,我不建议直接啃整个仓库,而是从三个地方入手。第一个是一个最小初始化示例的完整代码,搞懂它的启动流程;第二个是数据结构目录,弄清楚工作簿 JSON 的字段定义;第三个是命令注册相关的目录,试着实现一个自定义命令,比如批量给选区加边框。把这三个模块读透后,再去看渲染引擎与协同模块,就会顺畅很多。
有一点值得欣慰的是,Univer 的模块边界划分得比较清楚。即使我们不打算深入贡献核心代码,只作为使用方,也能通过插件接口完成大部分业务定制。这样维持源码的可维护性就不再是核心团队的内部事务,而是每个使用者的共同收益。
6.3 我的个人体会
把 Univer 引入生产项目之后,我最大的感受是:在线表格这个领域,终于有了一个可以拿来做长期投资的开源底座。它既没有把自己做成一个封闭的黑盒,也没有把全部业务逻辑堆在 Demo 里,而是把“公式、渲染、协同、插件”这些基本功分门别类地做扎实。对于预算有限又不想被商业授权绑架的团队来说,这种自由度极为珍贵。
最后送上一句我踩过很多次坑后的心得:在 Univer 项目里,永远不要绕过命令系统直接去修改内部模型对象。哪怕你直接改模型快速实现了效果,下一次升级版本就可能会被底层结构变化掀翻。正确做法是找到对应的 Command 或 API,让数据变更走标准通道。刚开始会觉得多写两行代码很麻烦,但长期维护时,你会发现这是保持项目可升级、可维护的最有效策略。表格业务从来不是只写一次就完事的功能,它会在你的产品里活很多年,选对底座、走对架构,后面的路真的会顺很多。