最近在做在线表格技术选型,翻遍各种资料后,我几乎把注意力都放到了 Univer 上。搜索“univer”和“univer 在线”的人不少,这类人群大多是产品技术团队,想找一套能嵌入自家业务、又敢用于生产环境的在线表格方案。Univer 不是什么简单的开源 Excel 组件,它背后是一整套可编程的办公套件基础设施。这篇内容我按“调研—跑通—踩坑—选型”的顺序来写,把 Univer 的定位、架构、接入步骤和真实体验梳理一遍,给正在选型或准备二次开发的人一个相对完整的参考。
1. Univer 到底是什么,为什么表格开发者都在聊它
1.1 它定位是“办公套件基础设施”,不只是一个普通组件
很多团队第一次接触 Univer 时,会下意识把它和普通的表格 npm 包归类到一起:能渲染格子、能写公式、能导出 Excel,好像就完了。但实际上 Univer 的野心要大得多。它的项目定位是开源、高效、可扩展的 Office 套件及基础设施,不只是做 Sheet,设计目标里还包含 Doc、Slide,也就是把文档、表格、幻灯片都纳入同一套底层框架。这意味着你买的不是某个功能点,而是一整套底层能力。
这种定位带来的直接变化是:你可以像使用积木一样组装模块。项目里不需要表格,但需要一个公式计算引擎,可以把 Univer 的 Formula 引擎单独拿出来跑;需要文档编辑,可以注册 Doc 模块;需要用户在前端做数据录入又要求协同,可以在同一套命令系统里扩展。对我这种做中后台产品的人来说,这套东西最大的价值是省掉了大量重复轮子,同时也给了足够的定制空间。
在写业务代码时,我明显发现 Univer 里的概念和普通无关组件很不一样。它不是用一个<table>标签去模拟表格,而是用 Canvas 绘制单元格,通过一套渲染引擎来管理和刷新视图。数据和视图之间隔着一层很明确的模型层,所有操作最终都会落到命令系统里。这个设计让它在做撤销重做、协同编辑、跨端一致性时都比传统 DOM 方案轻松很多。
1.2 和 Google Sheets、WPS 那种体验相比,Univer 到底到了哪一步
聊在线表格,必然绕不开 Google Sheets 这样的标杆产品。拿 Univer 和它对比,不能只看表面功能列表。从交互体验角度,Univer 已经覆盖了大部分日常表格能力:单元格编辑、行列拖拽、排序筛选、合并拆分、条件格式、数据验证、冻结窗格、查找替换、图表、迷你图、数据透视表,这些基本都是开箱可用。我在实测里拿一个中型表格做过操作,滚动流畅度、框选手感、公式自动补全这些基础体验已经接近原生表格应用的感觉,不会像一些老开源项目那样卡顿明显。
但这不代表它已经能完全替代桌面 Excel。复杂功能如明细表分类汇总、切片器、宏录制、高级数据透视布局,在浏览器里本身就有天然限制。Univer 的理念是把基础交互和业务扩展能力做扎实,把“可编程”作为核心优势。比如你想做一个“选中区域后弹出行业特定的分析面板”,Univer 的插件机制可以让你在不侵入源码的情况下挂上自己的 React 组件。这类扩展能力很多时候比某个冷门 Excel 功能更重要,因为产品经理真正关心的往往是业务闭环,而不是把一个桌面软件 100% 复制到浏览器里。
1.3 为什么“做一个表格编辑器”这件事尤其难
很多开发者第一次想自己写表格编辑器时,都会低估难度。三五个人的团队如果从零开始做,光是一个可靠的公式引擎就能消耗数月的时间。Univer 这种项目的价值就在于把无数工程问题前置处理掉了,比如:单元格区域范围如何和普通编程模型协调、公式循环引用怎么检测、复制粘贴时格式和公式引用如何重新计算、撤销栈在跨工作表操作时怎么保持稳定。这几个问题每一条都有大量边界条件,如果没有专门团队,很难在业务迭代压力下维持质量。
今天开源的表格编辑器其实不少,但多数迭代都停在了某个能用的阶段,后续再没有维护。Univer 到现在仍然保持较高活跃度,核心团队还在持续发版,这也是我最终愿意花精力深入研究它的原因之一。毕竟你在生产环境里上了一个项目,最怕的就是框架本身停止维护,风险只能自己扛。
2. 从零跑通一个可编辑工作簿:接入流程与细节
2.1 安装依赖与样式引入
Univer 的包管理是基于 npm 的,目前推荐方式是通过预设包(presets)来快速上手。我接入时使用的依赖大致如下:
npm install @univerjs/presets @univerjs/presets-sheets @univerjs/core如果只用表格,而且不需要自定义复杂插件,这些预设包已经够用。预设本身是插件的高层集合,会把渲染引擎、公式引擎、UI 组件、导入导出等能力一次性装配好。这种方式对普通业务开发相当友好,省去了逐个引 plugin 的麻烦。
装完包之后,一个容易踩坑的点是样式引入。Univer 的 UI 组件自带样式文件,如果你按照某些旧版本示例只写 JS 不引 CSS,页面打开后会是白屏或者完全无样式。当前版本可以参考如下引入方式:
import '@univerjs/presets/lib/styles.css';不同版本的具体路径可能会有调整,但核心原则是必须在入口处引入官方样式。如果你的项目用了 CSS 模块化处理,建议把 Univer 的样式放在全局样式中,不要打包到局部作用域里,否则内部组件类名被处理后会找不到对应规则。
2.2 初始化一个最小工作簿实例
在完成依赖和样式引入之后,初始化代码比我想象中简洁。下面的示例基于我接入时的 API 版本,具体方法名可能随版本演进变化,但整体思路是通用的:
import { Univer } from '@univerjs/presets'; import { UniverPresetSheets } from '@univerjs/presets-sheets'; import { UniverInstanceType } from '@univerjs/core'; const univer = new Univer({ container: 'app', presets: [ UniverPresetSheets({ header: true, toolbar: true, }), ], }); univer.createUnit(UniverInstanceType.UNIVER_SHEET, {});container填的是页面上 DOM 元素的 id,也可以用实际的 DOM 节点。createUnit这一步是创建工作簿单元,它和普通的前端组件初始化不一样:Univer 内部支持多实例、多工作簿,你可以创建多个文档单元然后在同一个页面里切换管理。注意,调用完createUnit之后页面里才会出现可编辑的表格区域,漏掉这一步就会看到一片空白。
如果你是更早的版本或者想用底层 API,方式也类似。核心点始终是创建一个 Univer 实例,注册渲染引擎和 UI,然后创建对应类型的文档单元。我对新项目的建议是直接使用预设包,省去逐个插件注册的繁琐过程,也避免插件缺失导致功能不完整。
2.3 在 React/Vue 页面里挂载和销毁
现在多数业务项目都是 React 或 Vue,Univer 本身不限定框架,所以接入时需要自己对生命周期做一次封装。我在一个 React 项目里是这样处理的:
import { useEffect, useRef } from 'react'; import { Univer } from '@univerjs/presets'; import { UniverPresetSheets } from '@univerjs/presets-sheets'; import { UniverInstanceType } from '@univerjs/core'; export function SheetEditor() { const containerRef = useRef<HTMLDivElement>(null); const univerRef = useRef<Univer | null>(null); useEffect(() => { if (!containerRef.current) return; const univer = new Univer({ container: containerRef.current, presets: [UniverPresetSheets()], }); univer.createUnit(UniverInstanceType.UNIVER_SHEET, {}); univerRef.current = univer; return () => { univer.dispose(); univerRef.current = null; }; }, []); return <div ref={containerRef} style={{ width: '100%', height: 600 }} />; }这里必须强调一个细节:createUnit如果放在 React 的 effect 之外被重复调用,每次都会创建新的工作簿,第二次可能不会顶掉第一个,而是产生一个多文档环境,表现上就是页面里出现多个单元或者行为诡异。所以在封装组件时,一个组件生命周期里只创建一次 Univer 实例和一次文档单元是基本要求。
容器高度也需要注意。Univer 的渲染机制会把容器当做一个固定尺寸的画布区域,如果容器高度是 0 或者没有显式设置,页面往往表现为不渲染或只渲染一半。给我的经验是,容器一定要设置具体宽高,单位用 px 或百分比均可,但必须由外部明确指定,不能依赖内部内容自动撑开。毕竟,Canvas 渲染不像 DOM 流式布局那样可以把高度“撑”出来。
3. 架构拆解:渲染引擎、公式引擎、命令系统如何分工
3.1 为什么用 Canvas 而不是 DOM 来画表格
运行 Univer 时,你会感觉到单元格内容并不是传统网页节点,它是由一个基于 Canvas 的渲染引擎绘制的。这个选择看起来技术性很强,但本质原因很简单:当表格达到数万行、数十列时,DOM 节点数量会直接拖垮页面性能。Canvas 把整块内容绘制到一张画布上,由渲染引擎自己控制哪些区域需要重绘,哪些可以复用缓存,滚动时只需要更新视口内的绘制结果。
这带来一个直观体验:在几万行数据里不停滚动,Univer 依然能保持比较好的帧率。如果用 DOM 渲染,每个单元格都在维护独立的节点,浏览器布局计算量会随可见单元格数量线性增长。这也是为什么 Google Sheets 这类现代表格产品都走 Canvas 路线的根本原因。它们不只是要做成“网页上能用”,而是要保证巨型数据的交互流畅度。
当然,Canvas 方案也有代价,最明显的就是“不能被浏览器无障碍树识别”。表格单元格里的文本如果直接画在画布上,屏幕阅读器是无法逐个读取的,因此 Univer 会在 Canvas 之上维护一个语义层或者通过其他方式兼容无障碍需求。但也正因为有画布层,它也保留了在画布上层叠自定义图形、批量画图表的能力。比如你可以用渲染 API 在某个单元格区域上绘制自定义的高亮框,而不是用绝对定位的 div 去覆盖,这种方式在性能上要干净很多。
3.2 命令系统:为什么全部交互都是“命令”而不是直接改数据
Univer 内部有一套成体系的命令机制。我们执行复制粘贴、设置格式、插入行列等操作时,表面上看到的结果是单元格变化了,实际上背后是几个命令被依次执行:先是 UI 操作触发了某个 Command,Command 内部再把具体修改封装成更底层的 Operation,真正落库的是后者。
这种分层有一个直接好处:撤销重做变得非常稳定。只要每个操作都遵循“执行前记录反向状态、执行后留下变更记录”的模式,撤销栈就可以通用地处理所有功能,不需要为复制粘贴、公式修改、样式变更分别写一套撤销逻辑。实测中,Univer 的多步撤销和重做表现不错,在连续修改单元格内容和合并单元格之后,撤销路径基本没有出现过状态错乱。
命令模型也是协同编辑的基础。多端同步时,每个客户端只需要把本地生成的命令序列推给服务端,服务端再按时序广播给其他端,其他端执行同样的命令后状态就保持一致。这种基于操作转换的协同思路已经有相当成熟的理论和实践支撑,Univer 在底层面向协同做了对齐设计,而不是把协同当成后期补丁。
对于二次开发来说,命令系统的意义是:你不需要通过复杂的 API 去“调用某个函数”来改变内容,而是可以注册自己的命令,并在命令里读取当前文档快照、做校验、再提交变更。这个设计给了我很大的自由度。例如我有一个配置表格的需求,需要在用户修改 A 列时自动校验 B 列是否有冲突,我可以写一个自定义 Command 包一层校验逻辑,再执行原生的单元格修改命令,整个过程和 Univer 自带的撤销、协同都能无缝衔接。
3.3 公式引擎独立运行的意义
Univer 的公式引擎被设计成可以和 UI 分离。这并不是一个炫技的设计,而是有实际场景需要的。我的项目里有一些异步任务,需要根据服务端下发的数据自动生成结果,我不希望每次都要打开一个浏览器页面才能计算,而是希望在后端 Node 服务里直接创建 Univer 工作簿、填入数据、设置公式,然后拿到计算结果。
这种场景下,如果公式计算逻辑和 DOM 强绑定,基本不可能在服务端运行。Univer 通过把数据模型、公式引擎和 UI 层解耦,让 Node 环境也可以创建文档内存实例,执行公式、读取计算后的单元格值。这个能力让表格类产品的服务端生成、数据校验、权限校验都能和前端共用同一套逻辑,避免了“前端算一种结果、后端算另一种结果”的经典问题。
拿我一个人维护的报表导出功能举例:服务端需要给用户导出带有公式结果的 CSV。以往的做法是前端先把 Excel 公式算完再导出,结果就依赖用户本机有没有打开页面。现在则可以在服务端直接用 Univer 公式引擎读入模板,填充参数,算出结果,再走导出流程。这个思路不仅减少了前端负担,也大大提高了数据的一致性。
4. “Univer 在线”不只是个口号:协同能力的真实边界
4.1 在线表格协同要解决的三件核心事
很多人搜索“univer 在线”,其实想找一个可以直接体验的在线表格。但真正决定产品能否支撑在线的,远不止“浏览器里能打开”这么简单。一个可靠的多人在线表格,至少需要解决三件核心问题。
第一,操作的一致性。两个人同时编辑不同单元格,系统要保证最终状态一致;两个人同时编辑同一个单元格,系统要决定谁的操作优先,或者如何合并。这就是协同算法要解决的 OT(操作转换)或 CRDT(无冲突复制数据类型)问题。第二,状态的持久化。文档数据不可能只存在某个浏览器内存里,需要同步到服务端存储。第三,权限和冲突提示。谁能编辑、谁会收到谁正在编辑的提示、数据提交时是否需要锁,这些是产品层面绕不过去的问题。
4.2 Univer 在协同层面做了哪些事
Univer 的架构里,协同并不是一个额外挂在边上的插件。它的所有本地修改都体现在命令系统上,这就让它很适合把“命令流”作为协同同步的最小单元。你在一个客户端插入一行,本质上是执行了一个插入行命令,这个命令被打包后可发送给服务端,再广播给其他客户端。其他客户端收到后执行同样的命令,理论上就可以复现同样的修改。
Univer 也设计了服务端协议的相关模块,用来描述客户端和服务端之间的命令序列交互。这样看来,它的底层通道已经为协同准备好了。但要注意,官方提供的是基础设施和协议规范,不包含一个可以直接包起来就用的完整协同服务端。要实现真正的多人实时编辑,你仍然需要自己做服务端的状态存储、操作序列管理、冲突处理服务,甚至鉴权和房间管理。这不是 Univer 的缺陷,而是它作为可嵌入基础设施的定位决定的——每家业务的协同策略和存储模型不一样,它希望把核心机制给你,把业务化部分留给你。
4.3 自部署“Univer 在线”时,你需要补齐的工作
如果你的目标不是用官方在线 Demo,而是要在自己的系统里实现一个“在线表格”,那么工程结构大概会是这样:前端嵌 Univer,负责编辑和渲染;服务端负责文件存储、协同通道和权限控制;两者之间通过 WebSocket 或类似的长连接通道来同步命令序列。
我自己在验证时采用了一个相对简单但可靠的方案:客户端每次提交操作,不再依赖复杂的协同算法,而是先把操作打到服务端一个版本号队列里,由服务端按顺序把操作广播给同房间内其他客户端;操作本身再通过乐观锁做冲突检测。如果两个人同时改同一个单元格,后提交的一方会被服务端告知冲突,再由前端提示或做二次确认。这种方案比完整 OT 简单,但足以保障大多数企业内部场景的数据一致性。
如果你真的需要多人同时编辑同一个单元格时也能自动合并,那就得在服务端引入 OT 转换或者 CRDT 算法。这样做会显著增加工程复杂度。Univer 的底层模型能匹配这种体系,但算法落地还是要自己来。对大部分场景,我建议先做版本号 + 冲突检测,跑通业务后再评估是否需要无冲突协同。
5. 实测中的常见坑,以及绕过方案
5.1 白屏、尺寸和初始化顺序问题
我接入 Univer 时遇到的第一个坑,是页面里只有一片空白,浏览器控制台也没有明确报错。排查后确认,问题出在容器没有固定高度。这在上文已经提过,这里再次强调:因为渲染引擎用 Canvas,它需要确定画布大小,容器高度为 0 时画布高度也变成 0,自然看不到任何东西。
第二个坑是重复创建实例。在调试热更新时,组件 effect 反复执行,每次都 new 一个 Univer,最后页面上出现两个工具栏甚至互相遮挡。解决方法是组件卸载时调用univer.dispose(),同时确保 effect 的清理逻辑完善。在 Vue 里也一样,onBeforeUnmount阶段要显式销毁实例,不要把清理交给垃圾回收。
另外,初始化时机最好放在页面容器渲染完成后。如果在DOMContentLoaded之前就创建实例,容器可能还不存在。如果你用的是 Vue 的v-if来控制页面展示,务必等待 DOM 实际挂到页面上再触发初始化。
5.2 导入导出 XLSX 的兼容性
Univer 的导入导出能力覆盖了常见的 xlsx、csv 类型,官方也提供了对应插件或预设支持。基础场景很好用,比如把二维数组数据 export 成 xlsx、读取本地上传的 xlsx 并渲染,这些都能顺畅跑通。
不过,复杂的 Excel 文件导入后是否 100% 还原是另一个问题。实测里,带复杂图表、跨工作表引用、透视表、复杂样式的老版本 xlsx 文件,在导入后偶尔会出现部分格式丢失或者图表位置偏移。原因不难理解:Excel 文件格式本身极其庞杂,严格到每个字节都要兼容。就算桌面版办公软件打开某些第三方生成的 xlsx 也会出现提示,Univer 能做到大部分还原已经很难得。
给你的建议是:导入导出前先做“文件兜底”。比如用户导入完 xlsx,系统后台最好把原始文件保留一份,避免前端解析后覆盖原文件。如果业务流程对格式还原要求极高,比如金融表单或政府报表,那么建议在 Univer 之上再做一层模板校验,导入后先检查关键单元格是否有值、文本格式是否符合预期,再决定是否允许进入下一步。这个思路远比期待框架 100% 完美还原所有 Excel 特性更可行。
5.3 输入法、复制粘贴和移动端体验
中文输入场景是 Univer 这类浏览器表格产品必须处理的细节。我在输入中文时发现,如果快速连续输入拼音,编辑框的 composition 事件如果没有处理好,会出现字母上屏或者候选词顺序错乱的问题。Univer 的编辑器组件已经考虑到 IME 场景,但在嵌入到自己的表单、做了受控输入绑定之后,还是可能被外部状态影响。建议测试重点放在“中文输入 + 数字字母混输 + 撤回”这条主链路上。
复制粘帖也是一处高频坑。从 Excel 里复制一块区域,粘贴到 Univer 中,是否能保格式、保公式、保样式,取决于数据解析的 MIME 类型。默认情况下,文本格式和基础表格内容可以正常还原,复杂的条件格式、列宽自定义则可能不被完全保留。如果业务上要求“从 Excel 粘贴进来后和原排版一模一样”,建议在接入前先做一轮 POC,用你们业务中最复杂的文件跑一遍。
移动端适配也别掉以轻心。Univer 的交互为鼠标键盘做了很多优化,但触屏上的单元格点选、滚动缩放、长按右键菜单等,都需要额外的适配工作。如果目标用户主要用手机浏览器访问表格,我不会推荐直接拿默认配置上线,至少得针对触屏做 UI 层调整,或者干脆给移动端做一个简化录入界面。
5.4 包体积和首屏性能的优化思路
Univer 功能全面,代价就是基础包不小。如果你的产品对首屏加载速度非常敏感,直接全量引入预设大概率会被性能指标挑战。我第一次集成时,没做任何懒加载,首屏加载时间明显上升。后来做了两步优化:一是把 Univer 相关代码用动态 import 拆到独立 chunk,只在用户打开表格页面时才加载;二是在表格页展示一个轻量骨架屏,把其余业务资源优先解析完毕。
如果你只使用表格,不需要文档和幻灯片,可以用底层包按需注册插件,而不是一次性引入所有预设。Univer 预设是为了方便而存在的,但它的确是面向通用场景的,业务只需要一半能力时,底层包方式反而更有利于控制体积。按需引入后,构建工具还能基于模块依赖做 tree shaking,进一步减重。
6. 选型对比:Univer 与 Luckysheet、OnlyOffice、SpreadJS
6.1 各项能力横向对比
我在选型时重点对比了四类方案:Univer、Luckysheet、OnlyOffice、SpreadJS。这四类代表完全不同的路线。Univer 是可嵌入、可编程的办公套件基础设施;Luckysheet 是纯前端表格开源方案;OnlyOffice 是可自托管的完整办公套件;SpreadJS 是商业表格组件。为了直观,我做了一个对比表:
| 维度 | Univer | Luckysheet | OnlyOffice | SpreadJS |
|---|---|---|---|---|
| 开源程度 | 开源,核心包可用 | 开源,代码可看 | 源码不完全开源,社区版有限制 | 商业授权 |
| 定位 | 可嵌入的 Office 套件基础设施 | 纯前端表格编辑器 | 完整自托管办公套件 | 商业级表格控件 |
| 表格渲染 | Canvas 渲染,性能好 | Canvas + DOM 混合 | Canvas 渲染 | Canvas 渲染 |
| 公式引擎 | 独立引擎,支持服务端运行 | 有基础公式实现 | 完整且经过长期打磨 | 成熟且性能优秀 |
| 协同能力 | 底层命令流支持,需自建服务端 | 协同能力弱,主要单机 | 自带协同服务端,开箱即用 | 协同需要配合服务端组件 |
| 二次开发 | 插件化设计,扩展灵活 | 有一定插件机制 | 扩展主要靠 API 和服务层 | API 完整,偏控件级 |
| 部署成本 | 前端 SDK + 自定义服务端 | 前端为主,部署简单 | 服务端较重,部署运维成本高 | 需要采购授权,部署视授权模式 |
从这个表能清楚看出,没有哪个方案是完美通吃的。Luckysheet 的最大优点是部署飞快、纯前端,但项目活跃度和协同能力存在明显短板;OnlyOffice 的表格能力非常完整,但它的形态更像一个独立产品,嵌入自家系统时通常要改造 UI 和操作习惯;SpreadJS 的控件成熟度很高,适合商业化复杂表格,但授权费用不低。
6.2 不同业务场景下我建议怎么选
如果把 Univer 放进真实业务场景里看,它的最佳适用对象是:有一定前端研发能力的团队,需要把表格深度嵌入到自己的产品流程中,而且未来明确有在线协作、多端同步、自定义交互这类需求。Univer 的插件化和命令系统会让二次开发更可控,Canvas 渲染也能保证数据量上来后的体验。
如果你的诉求只是在一个静态页面展示一个可编辑表格,不需要协同,也不打算深度定制,那么直接引入 Luckysheet 甚至一些成熟的数据网格组件就够了,完全没有必要上 Univer 这种重基础设施。虽然 Univer 也可以简配使用,但为了一个静态表格引入整套办公套件,性价比不高。
如果你的产品形态是一套完整的文档服务,需要文档、表格、幻灯片一体化,且要求开箱即用,OnlyOffice 更合适。它自带协同服务端,部署完就是一个可用的在线办公环境,适合不想自己拼装底层能力的团队。只是要注意,它的 UI 调整和 API 深度定制会比 Univer 受限一些。
如果你处于商业软件领域,表格能力是主要卖点,对性能和兼容性要求极高,也愿意付出授权费用,SpreadJS 是成熟的备选。它的文档、案例、技术支持都更完善,适合短期交付和商业兜底。反过来,如果团队想长期积累自己的表格中台能力,Univer 这类开源基础设施可能更符合战略需要,虽然短期工程投入更高,但不会受限于商业授权边界。
6.3 关于选型的一句大实话
我在多个项目里做技术选型最大的体会是:不要只看“谁功能最强”,要看“谁最适合你们团队的长期维护节奏”。功能最强的 OnlyOffice 拿给一个没有运维能力的团队就是负担;开源最活跃的 Univer 给一个想快速上线的小团队也会因为门槛而拖进度。选型一定要结合实际研发资源,先在核心业务场景里做一轮 POC,用真实文件跑通,再决定是否全量替换。
7. 最后再分享一个我常被问到的问题
很多人在初学 Univer 时会问,既然 Canvas 渲染性能那么好,为什么它不像 Excel 那样把全部 UI 都画在画布上?其实 Univer 的工具栏、菜单面板等部分依然采用 DOM 实现,只是数据区用 Canvas。这种“外 DOM、内 Canvas”的结构我反而认为是合理的。因为工具栏这类组件需要高频重渲染,但结构简单,用 DOM 即可完美支持无障碍、浏览器原生交互,成本也更低;而数据区复杂且滚动频繁,用 Canvas 收益最大。两层结合既兼顾了性能,又降低了整体开发维护成本。
在实际项目里,我还会给 Univer 包一层业务状态管理,而不是把所有状态都放在内部模型里。因为表格往往只是业务的一个步骤,用户在上面的操作最终需要映射成业务对象。比如一个库存录入页面,表格里改了哪些行,哪些是被删除的,哪些是新加的,这些是需要同步到业务后端的事务信息。用命令拦截或者监听变更事件来维护一份业务态,比在 Univer 模型里强行塞业务数据要清晰得多。这也是我折腾下来觉得最实用的建议之一。