产品说要让excel在线编辑,我是这样做的。

25,750 阅读4分钟

背景

最近公司项目有需求, 某导入功能, 想让客户选完excel文件, 直接将加载到web的excel编辑器中, 修改、确认, 之后上传导入。

以此来记录我的开发过程。

效果查看

Kapture 2023-04-13 at 13.37.05.gif

选择

就看到了这两个, 最后选择了Luckysheet, 看他的star比较多, 哈哈。

需求实现分析

分析一下整个流程。

其实大体就两步, 搞进去,抽离出来。

一、加载本地excel到web编辑器中

1、拿到本地excel文件流

2、转换为 Luckysheet 要的格式

3、new 一个 Luckysheet 实例, 挂在到对应标签上

完成以上就把excel加载进去了, 显示出来了。

在线编辑的事就是这个库帮咱们搞定了.

二、 从web编辑器导出文件流 上传

等客户在线编辑完成, 就需要点击一个按钮, 导出文件流, 确认并调接口上传

1、获取 Luckysheet里工作表的数据

image.png

luckysheet.getAllSheets()

2、将数据加工并使用xlsx或者exceljs导出文件流

导出为为arrayBuffer, 再将arrayBuffer转为Blob

3、调后端接口上传

开发实践

一、引入 lucky-sheet

有两种方式

1、官方文档里的cdn

这种加载有点慢

<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/css/pluginsCss.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/plugins.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/css/luckysheet.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/assets/iconfont/iconfont.css' />
<script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/js/plugin.js"></script>
<script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/luckysheet.umd.js"></script>

2、自己打包, 传到oss, 引入(推荐)

第一种第三方的cdn不稳定, 有时候很慢,还是建议,拉他的仓库,然后打个包,传到自己静态资源库, 来使用

clone 这个仓库 gitee.com/mengshukeji…

npm run builddist 传上去使用。

二、指定容器

这个是挂载 luckysheet 的容器, 它确保了被展示在何处。

id="luckysheet" 可以自定义, 和下面提到的 container: 'luckysheet' 保持一致即可

<div id="luckysheet"></div>

三、导入本地文件

1、 用elment的上传文件组件 选择文件

但是这里不上传,仅仅是用它选择文件拿到文件对象File

<div class="import-okr">
    <!-- ,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet -->
    <el-upload
        v-model:file-list="fileList"
        accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
        class="upload-demo"
        :before-upload="beforeUpload"
        action=""
        :show-file-list="false"
    >
        <button @click="uploadFile">上传数据</button>
    </el-upload>
</div>

2、beforeUpload 方法拿到文件

const beforeUpload = (file) => {
    console.log(file)
}

image.png

3、将文件流转换为lucky要的格式

这个是官方文档里推荐的转换包

github.com/dream-num/L…

安装转换工具

npm install luckyexcel

使用

file是文件对象, 回调函数里的 exportJson 是转换玩的luckySheet对象

// After getting the xlsx file
LuckyExcel.transformExcelToLucky(file, 
    function(exportJson, luckysheetfile){
        // exportJson就是转换后的数据
    },
    function(error){
        // handle error if any thrown
    }

4、将转换后的数据创建表格

// 将拿到的数据创建表格
luckysheet.create({
    container: 'luckysheet', // 挂载的dom的id名
    data:exportJson.sheets,
    title:exportJson.info.name,
    userInfo:exportJson.info.creator,
    lang: 'zh', // 设定表格语言
    myFolderUrl: window.location.href,
    showtoolbarConfig: {
        pivotTable: false,  //'数据透视表'
        // protection: false, // '工作表保护'
        print:false, // '打印'
        image: false, // 插入图片
    },
    showinfobar: false,
    options: {
        // 其他配置
        userImage:'http://qzz-static.forwe.store/public-assets/pgy_kj_pic_logo.png?x-oss-process=image/resize,m_fill,w_72,h_72', // 头像url
        userName:'Lucky', // 用户名
    }
});

完整代码

const beforeUpload = (file) => {
    console.log(file)
    // 转换工具, 将文件流转换为lucky要的格式
    LuckyExcel2.transformExcelToLucky(
        file,
        function(exportJson, luckysheetfile){
            isShowExcel.value = true
            console.log(exportJson)
            nextTick(() => {
                window.luckysheet.destroy();
                // 将拿到的数据创建表格
                luckysheet.create({
                    container: 'luckysheet', // luckysheet is the container id
                    data:exportJson.sheets,
                    title:exportJson.info.name,
                    userInfo:exportJson.info.creator,
                    lang: 'zh', // 设定表格语言
                    myFolderUrl: window.location.href,
                    showtoolbarConfig: {
                        pivotTable: false,  //'数据透视表'
                        // protection: false, // '工作表保护'
                        print:false, // '打印'
                        image: false, // 插入图片
                    },
                    showinfobar: false,
                    options: {
                        // 其他配置
                        userImage:'http://qzz-static.forwe.store/public-assets/pgy_kj_pic_logo.png?x-oss-process=image/resize,m_fill,w_72,h_72', // 头像url
                        userName:'Lucky', // 用户名
                    }
                });
            })
        },
        function(err){
            logger.error('Import failed. Is your fail a valid xlsx?');
        });
}

四、导出

1、利用 luckysheet.getAllSheets() 获取表数据

console.log(luckysheet.getAllSheets())

image.png

2、exceljs将上述对象转换为excel文件流

import Excel  from 'exceljs'
// 导出excel
const exportExcel  = async function (luckysheet) { // 参数为luckysheet.getluckysheetfile()获取的对象
    // 1.创建工作簿,可以为工作簿添加属性
    const workbook = new Excel.Workbook()
    // 2.创建表格,第二个参数可以配置创建什么样的工作表
    luckysheet.every(function (table) {
        if (table.data.length === 0) return true
        const worksheet = workbook.addWorksheet(table.name)
        // 3.设置单元格合并,设置单元格边框,设置单元格样式,设置值
        setStyleAndValue(table.data, worksheet)
        setMerge(table.config.merge, worksheet)
        setBorder(table.config.borderInfo, worksheet)
        return true
    })
    // 4.写入 buffer
    const buffer = await workbook.xlsx.writeBuffer()
    return buffer
}

3、 写个方法,执行上述两步

// 保存文件
const onClickSaveFile = async ( ) => {
    console.log(luckysheet.getAllSheets())
    const buf = await exportExcel(luckysheet.getAllSheets())
    const blob = new Blob([buf]);
    // $emit('file', blob)
    handleUpload(blob)
}

4、上传方法

从上一步拿到文件, 利用formData, 将生成的文件二进制流发给后端

const handleUpload = async(file) => {
    // isShowExcel.value = false
    const loading = ElLoading.service({
        fullscreen: true,
        text: '上传中,请稍等',
        background: 'rgba(0,0,0,0.1)'
    });
    try {
        const formData = new FormData()
        formData.append('file', file)
        // 伪代码
        const {code, data, message } = await IMPORT_OKR(formData)
        if(code === 1) {
            //...
        }
        loading.close()
    } catch (error) {
        console.log(error)
        loading.close()
    }
}

遇到问题

1、iconfont冲突

lucky-sheet这个项目里的iconfont类名和我项目里一样,导致有些被覆盖了. image.png

解决: 将他项目里 iconfont 换成 lucky-sheet, 相关类名也全部替换, 然后重新打包,再引入,即可解决

2、lucky-sheet层级不够高,无法编辑

image.png

elmentui和antd的一些组件层级比较高,所以, 让kucky的层级更高即可

解决: 增加下述css即可

.luckysheet-input-box { z-index: 2000; } .luckysheet-cols-menu { z-index: 2001; }

用过lucky-sheet的朋友们还遇到了什么坑? 评论区告诉我

最后

妥妥的都是站在巨人的肩膀上,感谢开发luckySheet的大佬们。

那么你们说产品下次是不准备搞协同编辑?

欢迎各位评论区交流

求赞