vue3 使用 Univer Sheets 电子表格组件

背景

部门要进行在线数据填报:excel表格样式不限;
因为要支持直接从excel直接粘贴,经筛选选择:Univer Sheets

Univer Sheets 官网地址
https://docs.univer.ai/zh-CN/guides/sheets
注:内置的导入、导出、打印为高级功能,收费

1、安装和配置

# 安装核心包
pnpm add @univerjs/presets

正常到这就可以了,但是我这边前台报react版本错误,所以去源码包看了一下版本,单独指定react的版本(如下图)

# 指定依赖的 react 
pnpm add react@18.2.0 react-dom@18.2.0 -D
# 最后的版本情况
{
  "dependencies": {
    "@univerjs/presets": "^0.8.2",
  },
  "devDependencies": {
    "react": "18.2.0",
    "react-dom": "18.2.0",
  }
}

注意:若指定了react的版本前台还报错,则修改 vite.config.js,指定 react 的路径,如下在 resolve 新增 react react-dom 的路径

#  vite.config.js
import {resolve} from 'path'

export default defineConfig(({command, mode}) => {
    const envConfig = loadEnv(mode, './')
    return {
        server: {
            .....
        },
        plugins: [
            ......
        ],
        resolve: {
            alias: {
                '~': `${resolve(__dirname, './')}`,
                '@': `${resolve(__dirname, 'src')}/`,
                react: resolve('./node_modules/react'),
                'react-dom': resolve('./node_modules/react-dom')
            },
        },
    }
});

若不指定路径,前端会报警告:

Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

在这里插入图片描述

2 编写基本样例功能

1)数据存储到浏览器缓存,再次打开加载缓存中的表格数据
2)启用、禁用表格编辑;
3)点击取消,销毁表格,并重新创建并加载
UI按钮模板是element-plus

<template>
  <el-row style="margin-bottom: 10px;background: white;padding: 10px 20px" justify="end">
    <el-col :span="18">
      
    </el-col>
    <el-col :span="6" class="d-flex">
      <div style="margin-left: auto;">
        <el-button v-if="!isEditable" type="primary" @click="setEditable(true)">编辑</el-button>
        <el-button v-if="isEditable" type="primary" @click="submitForm">保存</el-button>
        <el-button v-if="isEditable" @click="cancelEditable">取消</el-button>
      </div>
    </el-col>
  </el-row>
  <div ref="container" style="width: calc(100vw - 240px);height: 77vh;"></div>
</template>

<script setup>
import {onMounted, onBeforeUnmount, ref} from 'vue'

import {createUniver, defaultTheme, FUniver, LocaleType, merge, Univer} from '@univerjs/presets';
import {UniverSheetsCorePreset} from '@univerjs/presets/preset-sheets-core';
import UniverPresetSheetsCoreZhCN from '@univerjs/presets/preset-sheets-core/locales/zh-CN';

import '@univerjs/presets/lib/styles/preset-sheets-core.css';

const container = ref(null)

// univer 实例、操作api,因无需使用vue3特性,所以用的变量
let univerInstance = null
let univerAPIInstance = null

const STORAGE_KEY = 'univer-sheet-data'
const isEditable = ref(false) // 默认禁用编辑

// 设置编辑状态
const setEditable = (editable) => {
  const workbook = univerAPIInstance?.getActiveWorkbook()
  if (workbook) {
    workbook.setEditable(editable)
    isEditable.value = editable

    univerAPIInstance?.setUIVisible(univerAPIInstance.Enum.BuiltInUIPart.TOOLBAR, editable);
    univerAPIInstance?.setUIVisible(univerAPIInstance.Enum.BuiltInUIPart.FOOTER, editable);
  }
}

// 取消编辑
const cancelEditable = () => {
  loadData()
  setEditable(false);
}

// 创建并加载表格数据
function loadData() {
  // 1 加载表格前,先销毁已有的表格
  const fWorkbook = univerAPIInstance?.getActiveWorkbook();
  const unitId = fWorkbook?.getId();
  if (unitId) {
    univerAPIInstance.disposeUnit(unitId);
  }
  // 2 获取数据,并创建表格
  const savedDataStr = localStorage.getItem(STORAGE_KEY)
  const savedData = savedDataStr ? JSON.parse(savedDataStr) : null
  if (savedData) {
    univerAPIInstance?.createWorkbook(savedData)
    console.log('已加载 localStorage 中的表格数据')
  } else {
    univerAPIInstance?.createWorkbook({name: 'Test Sheet'})
    console.log('初始化新工作簿')
  }
}

// 保存数据至存储
const submitForm = async () => {
  const workbook = univerAPIInstance.getActiveWorkbook()
  const snapshot = workbook.save()
  localStorage.setItem(STORAGE_KEY, JSON.stringify(snapshot))
  console.log('表格已保存到 localStorage')
  setEditable(false)
}

onMounted(() => {
  // 初始化基本信息:参考 https://docs.univer.ai/zh-CN/guides/sheets/integrations/vue
  const {univer, univerAPI} = createUniver({
    locale: LocaleType.ZH_CN,
    locales: {
      [LocaleType.ZH_CN]: merge(
          {},
          UniverPresetSheetsCoreZhCN
      ),
    },
    theme: defaultTheme,
    presets: [
      UniverSheetsCorePreset({
        container: container.value,
        toolbar: true, // 工具栏
        footer: true // 底部
      }),
    ],
  })

  univerInstance = univer
  univerAPIInstance = univerAPI

  // 加载数据
  loadData()

  // 默认禁用编辑
  setEditable(false)
})

onBeforeUnmount(() => {
  univerInstance?.dispose()
  univerAPIInstance?.dispose()
  univerInstance = null
  univerAPIInstance = null
})
</script>

3、效果及评价

1)样式比较好,权限控制精细,未深入研究
2)测试的项目:打包从26M 变成36M,整个包新增相关较大
3)官方有按模块引用,这里没做精简引用,欢迎您测试,并留下评价
预览效果如下图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值