用户在浏览器里花四十分钟填完一张预算表,手指一滑碰到了刷新键。页面回到初始空白,输入、批注、调过的格式一起消失——如果系统没留"完整保存"的退路,这就是每次都会重演的事故。另一头,管理员做好了一套带公式和样式的报表模板,希望分支系统能直接加载,而不是照着文档手工重建。
这两个问题指向同一种能力:把整个工作簿连同全部状态打包成一个文件,需要时原样恢复。SpreadJS 为此提供了原生 ssjson 格式,核心是 Workbook 上的 toJSON 与 fromJSON 一对方法。
为什么这个细节重要
一张工作表远不止"格子里的值"。公式、样式、合并区域、冻结窗格、条件格式、数据校验,都是工作簿状态的一部分。若持久化方案要求把这些逐项拆开存库,就要为每类对象设计表结构、写转换代码,日后还得跟着维护。漏掉一项,恢复出来的表就和原来不一样,而且往往要到用户用到那一步才暴露。
ssjson 把问题简化成"一个对象、一个文件":它是 SpreadJS 的原生 JSON 序列化格式,纯文本、可直接交给后端存储。导出的不是截图式的结果,而是可继续编辑、可重新计算的活的工作簿。
SpreadJS 的实现思路
导出一侧,spread.toJSON() 把当前工作簿序列化为 JSON 对象,转成字符串后包成 Blob,再借助一个临时的 <a download> 元素触发浏览器下载:
function exportSsjson() {
let fileJson = JSON.stringify(spread.toJSON());
let eleLink = document.createElement('a');
eleLink.download = 'test.ssjson';
let blob = new Blob([fileJson]);
eleLink.href = URL.createObjectURL(blob);
document.body.appendChild(eleLink);
eleLink.click();
document.body.removeChild(eleLink);
}
导入一侧走标准文件读取流程:文件选择器拿到用户选中的文件,FileReader.readAsText(file, "UTF-8") 读成文本,JSON.parse 还原成对象,交给 spread.fromJSON(jsonObj),页面上的表格即刻变成文件里的样子。
几处值得注意的细节:
- 这对方法属于核心包,不依赖任何 I/O 插件;若目标是从
.xlsx等二进制 Excel 文件导入,才需要另行引入 I/O 插件; toJSON支持序列化选项,如ignoreFormula、ignoreStyle可按需剥离公式或样式,做"只发结构"的空模板很方便;fromJSON对应支持doNotRecalculateAfterLoad等反序列化选项;- 加载较大文件时,把
fromJSON包在suspendPaint()和resumePaint()之间可避免中间态反复重绘; - 调试残留和固定文件名进入生产前应移除或改为动态命名,并补上校验与异常处理。
可以扩展到哪些场景
- 模板中心:总部维护 ssjson 模板文件,各业务系统加载后填充数据;
- 草稿与暂存:把序列化结果定时写入本地或服务端,防误关误刷;
- 审批归档:提交时留存工作簿快照,事后可完整重现当时的表样和数据;
- 版本对比:JSON 是纯文本,两次保存之间的差异可以直接 diff;
- 离线场景:断网时导出 ssjson 带走,恢复网络后再导回系统。
给开发者的关键词
GC.Spread.Sheets.Workbook.toJSON / fromJSON、ssjson(SpreadJS 原生 JSON 序列化格式)、FileReader.readAsText、JSON.parse、Blob 与 URL.createObjectURL、a 标签 download 属性、序列化选项 ignoreFormula / ignoreStyle / doNotRecalculateAfterLoad、suspendPaint / resumePaint、JavaScript 电子表格控件。
小结
表格系统的持久化不必从零设计。工作簿级的序列化让"保存"回到最朴素的语义:导出是一个文件,导入是恢复现场。数据、公式、样式一体带走,前端几十行代码就能搭出存取闭环。