☰
开源在线表格开发实践:Univer 嵌入式电子表格全解析
2026/11/4 10:33:31 网站建设 项目流程

前后两三个月里,我接连在三个项目里看到同一个需求:网页里嵌一个能编辑、能算公式、能导Excel的表格。第一个是内部财务台账,第二个是数据填报平台,第三个是低代码后台的明细录入。需求文案写得五花八门,但翻译过来都是同一句话——“我们要一个在线Excel”。

第一次我差点自研,被各种公式边界、单元格合并、复制粘贴剪贴板处理直接劝退;第二次我试了老牌库,发现要么只做数据读取,要么交互像上个年代的产物;第三次我花了一个周末把 univer 接进去,从此这类需求基本变成我一个人两小时能交付的固定动作。这篇文章就把我从零接入 univer 的完整认知写出来,包括它替我们解决了什么、核心架构怎么理解、最快怎么跑通,以及那些在文档里看不到的落地教训。

1. 给我一个做在线表格的理由:univer 到底替开发者解决了什么

1.1 在线表格之所以难,不是难在“画格子”

很多开发对表格第一反应是:“不就是二维数组渲染成表吗?”真到动手才发现,Excel 能被一家公司迭代三十年是有原因的。你至少要处理这么几层问题:

  • 数据模型:单元格不只是值,还有类型、格式、公式依赖、合并单元格起止位置、行高列宽、条件格式规则;
  • 交互模型:选中态、拖拽填充、多区域选择、键盘导航、剪贴板粘贴后能自动改写公式相对引用;
  • 计算引擎:公式的依赖关系、循环引用检测、跨工作表引用、异步计算;
  • 序列化:既要读.xlsx,又要写出让别人能再编辑的.xlsx,不是简单塞个 XML 就能糊弄;
  • 性能:几万行数据时滚动不卡、输入不延迟,DOM 方案基本在万级单元格就开始露怯。

所以你会发现,市面上的方案各管一段:SheetJS 负责读写文件,Handsontable 负责网格交互,它们的定位都不是“替代 Excel”。真正想做到类似 Excel 的产品体验,得有一个项目把数据层、渲染层、公式引擎、交互层一整套做齐,univer 正好是这个位置的存在。

1.2 为什么选 univer 而不是继续用 Luckysheet

如果你在 2022 年前后接触过在线表格,大概率知道 Luckysheet。第一版 univer 确实也被很多人误会成“Luckysheet 换壳”。实际上两者的定位差异非常大:

  • Luckysheet 是一个偏“成品组件”的思路,业务代码需要围绕它的数据结构来转;
  • univer 从一开始就是“框架级”的设计,底稿模型、命令系统、渲染引擎全拆开,任何一层都能独立替换;
  • Luckysheet 近年的维护节奏明显放缓,而 univer 在 GitHub 上的迭代频率、社区活跃度和版本发布密度都更健康;
  • univer 把 Doc(文档)、Slide(幻灯片)、Sheet(表格)三种文档类型收进了同一套基础框架,这对做办公中台的公司来说很值钱。

说白了,如果你只是想临时在页面上展示一个可编辑表格,选哪个都行;但如果这个表格是你产品的核心能力,那必须选一个有长期演进能力的基础框架。univer 明确是走后面这条路的。

1.3 一套开源方案能省掉多少自研成本

我粗算过一个账:从零做一个“只带公式和导入导出”的在线表格,团队规模按 2 个前端加 1 个算法评估,保守估计 6 到 8 个月。就算只做完整 Excel 功能的 60%,这个工作量也会击穿多数中小团队的排期。而 univer 把这些能力都以开源形式开放了出来,你投入的是学习成本和集成成本,不是从零发明的成本。

更重要的是,univer 在架构上把“前端组件”和“业务后端”解耦了。前端能嵌入应用,配合任意后端存储。对于很多企业用户来说,“能不能部署在自己内网”比“功能多不多”更要紧,这一点在同类开源项目里执行得比较彻底。

2. 架构浅读:为什么 univer 适合被“嵌入”而不是被“封装”

2.1 无头核心:先有数据,后有界面

univer 的根包叫@univerjs/core,这个包里没有任何 UI 代码,只有文档模型、命令系统、实体、撤销重做这类基础设施。UI 层的插件再去订阅这些核心事件,把模型变化渲染到屏幕上。这个设计的直接好处是:你可以拿同一套数据核心,接不同的视图层。

举个例子:我们项目要求同一个电子表格数据,同时展示在 PC 端的管理后台和移动端的预览页。PC 端用完整的sheets-ui,移动端只写一个极简渲染层,监听核心数据变化后画到 Canvas 上。这种灵活性是“表格组件”永远给不了的,因为组件把数据和 UI 绑死了。

理解 univer,我建议你先记住一个公式:

univer = 数据模型(core 层)+ 交互渲染(ui 层)+ 扩展能力(plugin 层)

2.2 Canvas 渲染到底解决了什么问题

早期 Web 表格产品习惯用<table>或div拼格子的方式渲染,原因无非是 DOM 方便处理事件、方便写 CSS。但 DOM 的瓶子在大数据量下瓶颈很明显:几万行真实数据进来,光是创建几万个节点就足够让主线程瘫痪。

univer 的主力渲染层走的是 Canvas 2D 路线,就是把可视区域内的单元格一个个画在画布上,滚动时只重绘当前视口。你可以简单理解成“地图瓦片”的思路:地图不会把整个世界都渲染出来,只渲染当前屏幕能看到的那一块。所以 univer 在十万行、几十列的数据下滚动体验依然接近原生应用,这在传统 DOM 方案里几乎做不到。

别误会,Canvas 不代表不能做富交互。univer 的事件处理是“命中测试”:通过坐标反推算你点到了哪个单元格,再走核心命令系统去改数据。这套逻辑比 DOM 事件重定向复杂一些,但换来的是渲染性能上限的大幅提升。

2.3 插件机制:你的业务代码不该跟表格代码搅在一起

univer 的扩展机制是registerPlugin。每个业务能力都是一个插件,生命周期由 univer 统一管理。比如公式是一个插件,导入导出是一个插件,协同协议也是一个插件。这样有两个藏得很深的好处:

  • 不需要的功能可以从打包里剔除,控制包体;
  • 业务功能可以独立成插件,避免在表格源码上改来改去,升级依赖时不会冲突。

实际开发中我最常用的是自定义菜单和自定义工具栏。比如我们在表格顶部加了一个“提交审批”按钮,点完把所有编辑过的数据推给审批流。用插件写这部分逻辑就非常舒服:插件内部通过 command 执行setRangeValues,流程清晰,也不会污染社区源码。

如果你刚开始用,别急着改内部源码或 polyfill。先想清楚:我要增强什么能力,能否通过 univer 的 command 或 event 体系去实现。绝大多数需求都能在这层的边界内解决。

3. 从空目录到可编辑表格:二十行代码跑通 univer

3.1 环境准备与安装

univer 是纯 TypeScript 前端项目,没有后端依赖,这让我第一次接入时非常省心。前提条件很简单:

  • Node.js 18 及以上;
  • 主流包管理器 npm/pnpm 都行;
  • 浏览器是标准现代浏览器,不需要 WebGL。

如果是 React 技术栈,直接安装官方推荐的预设包:

npm install @univerjs/presets

注意:univer 的 0.x 版本 API 处在一个高频演进期,我平时都是固定一个大版本再升级,避免破坏性变更影响业务。建议项目里务必锁定package.json中的具体版本号,不要用^放任小版本漂移。

3.2 初始化一个最小实例

以 React 为例,最快能跑起来的代码如下。这里直接给完整可运行版本:

import React, { useEffect, useRef } from 'react'; import { LocaleType, Univer } from '@univerjs/presets'; import { UniverPresetSheets } from '@univerjs/presets/presets/sheets'; export default function SheetDemo() { const containerRef = useRef<HTMLDivElement>(null); useEffect(() => { if (!containerRef.current) return; const univer = new Univer({ locale: LocaleType.ZH_CN, presets: [ UniverPresetSheets({ container: containerRef.current, }), ], }); univer.createSheet('业务台账', { rowCount: 500, colCount: 20, }); return () => { univer.dispose(); }; }, []); return ( <div ref={containerRef} style={{ width: '100%', height: '80vh', border: '1px solid #e5e7eb' }} /> ); }

这段代码做了三件事:创建 univer 实例、把表格 UI 插件注册进去、在容器里生成一个 500 行乘 20 列的空白工作簿。univer.dispose()是很多新手容易漏掉的细节,组件卸载时如果不做清理,在路由切换频繁的管理后台里可能会叠出多个表格实例,内存和事件监听都会出问题。

3.3 在控制台里操作数据

没有业务场景的表格是玩具,univer 的数据操作核心入口在它的 command 体系里。给一个单元格写入值,最直接的方法是获取当前 active sheet 的操作对象:

const sheet = univer.getActiveUnit(); sheet.getCommandService().execute({ id: 'sheet.operation.set-cell', unitId: sheet.getId(), sheetId: sheet.getActiveSheetId(), range: { startRow: 0, startColumn: 0, endRow: 0, endColumn: 0 }, value: 'hello univer', });

不同版本的 command id 有可能调整,但套路是一致的:所有变更都走 command,而不是直接改内部模型。这样设计的好处是撤销重做、协同冲突处理都在 command 这一层完成,你的业务代码天然具备这些能力。

如果你想直接读取数据,我建议不要依赖 UI 层,而是通过核心模型遍历:

const workbook = univer.getActiveUnit(); const worksheet = workbook.getActiveSheet(); const cell = worksheet.getCellRaw(0, 0);

3.4 一个快速跑通的判断标准

我给自己定过一个验收线:一个全新项目接 univer,从安装到看到下图这种“能渲染、能点击、能输入、行数能滚动”的页面,二十分钟内必须完成。超过这个时间不是网络问题,就是你还没理解预设包的正确用法。真正花时间的从来不是跑通 demo,而是后面的业务适配和性能优化。

4. 业务接入时必须要关注的能力边界:公式、导入导出、协同

4.1 公式引擎:从“会算”到“算得快”

univer 的公式引擎是独立模块,这也是它和普通表格组件的核心差异。它内置了大量常用函数,覆盖数学、文本、逻辑、日期、查找引用等类型,基本的 Excel 公式在它上面能直接跑。

我最喜欢的一点是公式计算天然走异步和依赖链析出。意思是说,如果你有一片区域的公式互相引用,改动某个源数据时,它只重算受影响的下游单元格,而不是把整个工作簿从头扫一遍。这个设计在业务里很关键:一个两万行的成本计算表,我改了其中一个单元格的单价,UI 不会卡住,计算是在后台线程完成的。

如果内置函数不满足,univer 允许注册自定义函数。我们做过一个场景:表里要调用内部 API 查询“客户风险等级”再参与后续公式运算,写一个异步自定义函数就解决了。这类“表格公式 + 业务服务”的组合,是自研表格根本绕不过去的深水区,用现成框架倒是轻而易举。

4.2 导入导出:xlsx 不是简单文件读写

几乎所有客户提需求时都会说“我要能导入导出 Excel”。但你真要交付时才会发现,这个需求背后藏着一堆暗坑:

  • 原文件里带合并单元格、公式、图表、数据验证,导入后不能丢;
  • 导出后的文件拿回本机 Excel 打开,格式必须和页面上看到的一致;
  • 文件里有特殊日期格式、自定义数字格式,序列化稍不注意就变成科学计数法。

univer 的导入导出插件模块官方一直在完善,xlsx 和 csv 的互通是基本盘。我在实际项目中,导入导出都走了插件路径,没有自己去写解析。这里要记住一个边界:导入导出不是 100% 无损的,比如某些非常冷门的 Excel 特性(比如切片器、编程窗体)不一定支持。建议在项目文档里直接和业务方写明“支持常见 Excel 功能,超范围功能不保证”,提前管理预期,比上线后被测试追着报 bug 舒服得多。

4.3 协同编辑:别幻想开箱即用

univer 在线协同是它商业版和企业版的核心卖点之一,开源层面的前端协议也开始逐步铺开。但我在整合到公司私有化项目时,做的最重要的一件事就是:不要把协同当成一个前端插件。

协同至少需要四段链路:

  1. 前端把每次操作(command)包装成带时间戳的操作消息;
  2. WebSocket 网关把消息广播到房间内其他人;
  3. 服务端做操作转换(OT)或 CRDT 合并,保证多方编辑不冲突;
  4. 存储端落库,刷新后数据还能从持久层恢复。

univer 前端只是这条链路的起点。你的服务端需要设计“房间”模型、权限模型、在线状态同步、离线消息补偿。这块没有银弹。如果项目里只是“一个人录入、另一个人偶尔看一下”,我建议先不做实时协同,直接用简单的轮询加版本号判断,能省掉一大半后端复杂度。

4.4 表格形态之外:Doc 和 Slide 是同一个底子

univer 最让我觉得“架构值钱”的一点,是 Doc 和 Slide 与 Sheet 共用底层核心。未来如果业务要做在线 Word 编辑,或者做一个办公室套件式的产品,基于 univer 可以少走很多脚手架弯路。虽然目前表格是最成熟的一块,但这个产品方向本身就意味着更高的长期可靠性。

我也理解很多人现阶段只要表格。即便如此,架构上有这个完整度的开源项目,不必过分担心两年后“表格功能没人维护”的风险。

5. 生产环境的真实权衡:性能、包体、版本与体验优化

5.1 大数据量下的性能,不能只看首屏渲染

Canvas 方案在滚动渲染上的优势明显,但表格性能从来都是系统工程。我遇到过的真实问题包括:

  • 一次性设置大 range 的值时,如果用循环一格格 set,会把主线程卡死,正确做法是用批量 range 操作提交;
  • 条件格式规则定义多了以后,每次重绘的命中判断也会变慢,能静态化就静态化;
  • 复杂公式的跨表引用会指数级放大计算量,注意拆分工作簿或用公式分组。

我的原则是:业务数据能分页就分页,能把 10 万行变成 5000 行一定不要偷懒。表格框架本身再优化,也架不住业务逻辑把全部数据堆到一个 sheet 里还每条都配条件格式。

5.2 包体怎么控制

univer 的功能完整,代价就是包体不小。这在家宽网络下无所谓,但在政企内网、弱网环境里会直接影响首屏。

我实际采用的控制手段如下:

  • 按需注册插件,不用的功能模块不进打包;
  • 主业务路由做成异步加载,表格页面切到再下载;
  • 用构建工具的 manualChunks 把 univer 单独拆成一个 vendor chunk,让表格代码和业务代码分开缓存;
  • 静态资源走 CDN,但内网客户可以直接把产物底座放到本地。

这里有个隐藏细节:按需注册意味着“公式都没注册就贴一个=SUM(A1:A10)”会被当成纯文本,业务上需要在初始化时想清楚当前场景到底引进哪些能力,不能无脑全注册。

5.3 版本升级是最容易被忽略的“隐形坑”

univer 还在 0.x 阶段,技术心法可以学最新,但生产代码一定要冷静。我们团队固定了一套升级策略:

  • 每次只跨一个小版本升级,升级后先跑冒烟用例;
  • 把初始化、常见操作、导入导出三个用例写成自动化回归,升级前跑一遍;
  • 看到 release note 中出现Breaking Change字样的,提前看 migrations 文档;
  • 永远锁版本号,不锁版本的依赖迟早会在某个周五下午炸掉。

5.4 深度定制:主题、中文本地化、操作习惯

univer 的 UI 层提供了不少定制入口。我们实际配过:

  • 修改主题色变量,让表格和后台设计规范统一;
  • 设置中文语言包,并把“新建工作表”等菜单文案按公司语气改写;
  • 配置工具栏显隐,去掉“数据透视表”这类多数客户用不到的重功能,降低页面复杂度。

不要小看这些表面功夫。表格类产品的使用体验,用户感知最强的不是底层性能,而是“它跟我平时用的 Excel 像不像”“那些碍眼按钮能不能隐藏”。这一类定制,univer 给到的基础能力基本够用。

6. 围绕 univer 我实际会做的扩展方向

6.1 把它当成低代码平台里的“万能明细录入组件”

低代码平台最喜欢遇到“这个表单不知道怎么设计”的需求,落到最后基本都是表格。用 univer 做明细录入组件,比挨个控件配置要高效得多:整体选中、复制粘贴、公式联动、批量修改都天然支持。

我们在一个巡检系统里就这么干的:巡检项、负责人、计划时间、参考值全部做成一张工作底稿,后端拿数据时直接读取整个 sheet 区域内容,一次入库。用户反馈“终于不用一格一格填了”。

6.2 用它做数据回显和工作报告导出

很多后台系统都面临“数据不好看”的问题。与其写一堆前端图表库,不如允许用户把同源数据导到表格里自行分析。univer 在这里的价值是,让用户在网页里编辑、再导出 xlsx 作为汇报附件,图表、公式、格式都在同一个文件里。

6.3 配合后端做模板下发与收集

还有一个玩法是:提前做好一张带公式、数据验证、条件格式的模板表,下发到各业务部门填写,再收集回来统一解析。这个闭环在 univer 上很顺畅——模板在网页里直接渲染,填写完自动校验,兜底了原来 Excel 文件传来传去版本混乱的痛苦。

6.4 一点真心的落地提醒

最后提醒一件事:univer 是开源项目,但不是“免费的全包服务”。它给你的是一套能力框架,真正的业务适配、性能调优、服务端配套、体验打磨,仍然需要团队投入。别把它当成外包项目里的黑盒,越早把架构搞明白的团队,越能从这套框架里拿回性价比。

我自己在连续做完几个在线表格项目后,已经形成了一个固定心态:看到“在线 Excel”需求,先打开 univer 文档评估,而不是先打开脑洞。开源生态里能让你把这个需求稳稳接住的选择,其实并不多,univer 目前是最值得押注的那一个。

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

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

立即咨询