Univer 在线表格模块使用说明

2 阅读5分钟

本模块基于 Univer 封装了一套「在线表格 + 模板管理」能力,包含基础示例、模板中心、模板设计、模板应用四个页面,以及一个可复用的组合式函数 useUniverSheet。模板数据持久化在浏览器 localStorage,无需后端即可完整跑通。

目录结构

univer/
├── basic.vue                      # 基础使用示例(填充数据/只读切换/新增表/导出快照)
├── scenes.vue                     # 模板中心(模板列表的增删改查入口)
├── designer.vue                   # 模板设计(两步式:基础信息 → 表格配置)
├── apply.vue                      # 模板应用(加载模板快照并可导出)
├── components/
│   ├── DesignerBasicStep.vue      # 设计页第一步:模板基础信息表单
│   └── DesignerConfigStep.vue     # 设计页第二步:表格设计容器
└── core/
    ├── useUniverSheet.js          # Univer 实例的组合式封装(核心)
    └── templates.js               # 模板数据的读写与持久化

文件链接(Gitee 仓库)

文件说明
basic.vue基础使用示例
scenes.vue模板中心
designer.vue模板设计
apply.vue模板应用
components/DesignerBasicStep.vue设计页第一步:基础信息表单
components/DesignerConfigStep.vue设计页第二步:表格设计容器
core/useUniverSheet.jsUniver 实例组合式封装(核心)
core/templates.js模板数据读写与持久化

核心概念

  • 工作簿快照(workbookData):一份描述工作簿结构与内容的 JSON 对象,含 idnamesheetOrdersheets。模板保存的就是这份快照,应用页直接还原它。
  • unit id:即工作簿快照里的 id,Univer 内部用它唯一标识一个工作簿单元。同一个 unit id 不能被重复创建,重载前必须先销毁。
  • 懒加载初始化:容器被隐藏(v-show/v-if)时宽高为 0,此时无法正确渲染表格,需等容器可见后再初始化。

useUniverSheet 用法

基本调用

import { useUniverSheet } from "./core/useUniverSheet";

const {
  containerRef,      // 表格容器引用,必须绑定到 DOM
  workbookRef,       // 当前工作簿(展示用)
  activeSheetName,   // 当前工作表名称
  activeRangeText,   // 当前选区 A1 表示
  readyRef,          // 是否已初始化完成
  getWorkbook,       // 获取当前工作簿实例
  getActiveSheet,    // 获取当前工作表实例
  loadWorkbook,      // 加载/重载工作簿快照
  syncState,         // 手动同步状态到响应式变量
  ensureInitialized, // 确保实例已初始化(返回 Promise<boolean>)
} = useUniverSheet({
  workbookData: someSnapshot, // 可选:初始工作簿快照
  onReady: () => {            // 可选:实例就绪回调
    // 在这里写入演示数据、加载模板等
  },
});

模板必须把容器绑到 DOM

<template>
  <section ref="containerRef" class="sheet-host" />
</template>

容器需要有明确的尺寸(如 min-height: 720px),否则初始化会被跳过。

参数

参数类型说明
workbookDataobject初始工作簿快照,初始化成功后自动加载
onReadyFunction实例就绪回调,入参为 { univer, univerAPI, workbook, getWorkbook, getActiveSheet, loadWorkbook, syncState, ensureInitialized }

返回值

名称类型说明
containerRefRef表格容器引用,需绑定到 DOM 元素
workbookRefShallowRef当前工作簿引用(仅展示用)
activeSheetNameRef当前活动工作表名称
activeRangeTextRef当前选区 A1 表示法
readyRefRef实例是否初始化完成
getWorkbook()Function返回当前活动工作簿(FWorkbook)
getActiveSheet()Function返回当前活动工作表(FWorksheet)
loadWorkbook(data)Function加载/重载工作簿,返回 Promise
syncState()Function手动把工作簿状态同步到响应式变量
ensureInitialized()Function确保实例已初始化,返回 Promise

常见操作示例

写入数据与样式

const sheet = getActiveSheet();
sheet.getRange("A1:E1")
  .setValues([["项目", "负责人", "状态", "进度", "预算"]])
  .setBackground("#16324f")
  .setFontColor("#ffffff")
  .setFontWeight("bold");

切换只读

const workbook = getWorkbook();
workbook.setEditable(false); // true 为可编辑

新增工作表

const workbook = getWorkbook();
const sheet = workbook.create("工作表2", 80, 26);

导出快照

const workbook = getWorkbook();
const snapshot = workbook.save(); // 得到工作簿 JSON 快照

模板数据 API(core/templates.js

import {
  templateList,                 // 响应式模板列表
  basicWorkbookData,            // 基础示例工作簿数据
  createEmptyTemplateWorkbook,  // 生成空白模板工作簿
  getTemplateByKey,             // 按 key 查模板
  getFallbackTemplateKey,       // 取兜底模板 key
  getTemplateStats,             // 统计模板概况(表数/行/列)
  createTemplate,               // 新增模板
  updateTemplate,               // 更新模板
  removeTemplate,               // 删除模板
} from "./core/templates";
  • 所有数据保存在 localStorageuniver-sheet-templates 键下。
  • createTemplate / updateTemplatekey 冲突时会抛出 模板标识已存在updateTemplate / removeTemplate 在模板不存在时抛出 模板不存在,调用方需 try/catch 处理。

模板对象结构

{
  key: "chemistry-assay",        // 唯一标识(slug 化)
  name: "化学化验审批模板",
  category: "质量审批",
  description: "……",
  features: ["特性A", "特性B"],   // 字符串数组
  updatedAt: "2026-06-23T...",   // ISO 时间
  workbookData: { /* 工作簿快照 */ },
}

页面工作流

模板中心(scenes) ──新增/编辑──▶ 模板设计(designer) ──保存──▶ 模板中心
       │                                                      
       └──应用模板──▶ 模板应用(apply) ──加载快照/导出──
  1. 模板中心:展示模板列表,提供新增、编辑、应用、删除入口。
  2. 模板设计:第一步填写基础信息(名称/标识/分类/说明/特性),第二步在表格中完成结构设计,保存时把工作簿快照写入模板。
  3. 模板应用:加载选中模板的工作簿快照,保持设计时的原始结构,可重新加载、跳转编辑或导出快照。

注意事项与坑点

  1. 隐藏容器无法初始化:表格容器被 v-show/v-if 隐藏时宽高为 0,ensureInitialized() 会直接返回 false。模块内已用 ResizeObserver 兜底——容器从隐藏变为可见时自动重试初始化。分步表单中切到表格步骤后,建议 await nextTick() 再加 requestAnimationFrame 等待布局完成,然后调用 ensureInitialized()
  2. 重复 unit id 报错:同一个工作簿快照(相同 id)不能被 createWorkbook 两次,否则报 cannot create a unit with the same unit idloadWorkbook 已在重建前自动 disposeUnit 销毁旧工作簿,正常使用不会触发。
  3. 销毁前先解绑事件:销毁工作簿会让其引用失效,若残留的选区/活动表事件订阅仍在,回调访问 getUnitId 会抛空指针。loadWorkbook 内已在 disposeUnit 前解绑监听,自定义扩展时也需遵循「先解绑、再销毁」的顺序。
  4. 跨组件传递容器引用用函数 ref:把 containerRef(ref 对象)作为 prop 传给子组件时,会被 Vue 自动解包成 .value(初始为 null),导致子组件 :ref 绑定失效。应改为传一个回调函数(如 setContainerRef(el)),在子组件用 :ref="setContainerRef" 绑定。
  5. 资源回收useUniverSheetonBeforeUnmount 中已统一销毁事件监听、ResizeObserver 与 Univer 实例,页面卸载无需手动清理。