Univer 在线表格模块使用说明

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

目录结构

bash 复制代码
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.js Univer 实例组合式封装(核心)
core/templates.js 模板数据读写与持久化

核心概念

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

useUniverSheet 用法

基本调用

js 复制代码
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

vue 复制代码
<template>
  <section ref="containerRef" class="sheet-host" />
</template>

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

参数

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

返回值

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

常见操作示例

写入数据与样式

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

切换只读

js 复制代码
const workbook = getWorkbook();
workbook.setEditable(false); // true 为可编辑

新增工作表

js 复制代码
const workbook = getWorkbook();
const sheet = workbook.create("工作表2", 80, 26);

导出快照

js 复制代码
const workbook = getWorkbook();
const snapshot = workbook.save(); // 得到工作簿 JSON 快照

模板数据 API(core/templates.js

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 处理。

模板对象结构

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

页面工作流

scss 复制代码
模板中心(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 实例,页面卸载无需手动清理。
相关推荐
lichenyang4531 小时前
WebRuntimePage 拆分:从大页面到运行时控制器
前端
竹林8181 小时前
从报错到跑通:我用 @solana/web3.js 开发 Solana 钱包连接踩过的三个坑
前端
MariaH1 小时前
Node中操作MySQL
前端
还有多久拿退休金1 小时前
一个 var 让整个团队加班到凌晨——JS 闭包的那些暗坑
前端·javascript
weedsfly1 小时前
用了 React/Vue 之后,这些 DOM 操作的坑你踩过几个?
前端·javascript
Asize1 小时前
Ajax 入门:从 JSON 序列化到 XMLHttpRequest
前端·javascript·前端框架
林希_Rachel_傻希希1 小时前
react hooks速通笔记
前端
Csvn2 小时前
🚨 组件卸载后还在 setState?一个被你忽视的内存泄漏和报错根源
前端
乘风gg2 小时前
AI GenUI 真正落地时,前端到底要做什么?
前端·ai编程·cursor