likes
comments
collection
share

基于luckysheet,实现表格编辑,文件处理后,我把组件封装成了一个vue插件

作者站长头像
站长
· 阅读数 14

背景

最近项目中一个模块有一个excel文件导入的功能,导入数据可能会失败,失败的数据通过接口获取然后会在table中显示出来,数量不详。在之前,可能需要后台提供一个接口将数据包装成excel文件下载下来,修改完再导入进去直到完成。领导觉得这样做有点繁琐,下载又修改又导入,对用户不是很友好。能不能在系统上做到嵌一个excel直接修改完点击保存然后直接导入?可能会问了,直接在列表上编辑不行吗?一是数量肯会比较大,列数不固定,二是后端只提供了导入文件接口 基于luckysheet,实现表格编辑,文件处理后,我把组件封装成了一个vue插件

目标

  • 找到一个excel插件,嵌入系统
  • 将表格数据导入到excel中,进行编辑
  • 编辑完成,调用导入接口,将excel中文件传入,所以要获取当前excel文件

调研

市面上有一个插件可以满足这个要求,那就是luckysheet,是一个比较成熟的类似excel的在线表格,配合luckyexcel可以实现导入导出。

luckyexcel有一个方法transformExcelToLucky,可以将excel文件处理成兼容luckysheet所需的数据格式,但是我们获取到的是接口返回的tableData,一个数组。若是能将tableData转成file文件,就可以调用这个方法将接口返回的数据直接塞进插件中。【其实也可以将tableData直接处理成luckysheet的数据格式,但是我觉得麻烦(懒),后续我也有封装导入excel的函数方法,所以说直接用写好的就行,嗯,是这样的】

编辑完成后,需要将luckysheet中的数据再导出成一个file文件,这样就可以调用我们的导入接口了。

可以看一下大致的效果,当然数据是随意写的

基于luckysheet,实现表格编辑,文件处理后,我把组件封装成了一个vue插件

实现

安装luckysheet

官网并没有提供依赖的形式,不能直接用npm安装。提供了cdn以及本地安装的方式,这里我由于部分原因选择了本地安装。去官网将主分支最新代码下载下来,然后build之后得到dist文件夹,将dist文件夹移植到项目中(若是公司有限制,可能需要用公司cdn转一道,没有则不需要)

基于luckysheet,实现表格编辑,文件处理后,我把组件封装成了一个vue插件

完事按照教程可以进行创建

tableData塞进luckysheet中

luckyexcel

  1. 首先,我先写了一个将file文件导入luckysheet的方法,为后续处理tableData铺路。这里需要用到luckyexcel这个插件了,将上传的文件也就是得到的file格式对象,通过transformExcelToLucky这个方法可以转成luckysheet格式数据,第二个参数是一个函数,参数是处理得到的可以luckysheet创建所需的数据

基于luckysheet,实现表格编辑,文件处理后,我把组件封装成了一个vue插件

import * as le from 'luckyexcel'

/**
 * 将excel文件导入excel组件
 * @param {*} file 导入的excel文件
 * @param {*} defaultWidth 默认单元格宽度300
 */
export const transformFileToLucky = (file, defaultWidth = 300) => {
    le.transformExcelToLucky(
        file,
        function(exportJson, luckysheetfile) {
            // 获得转化后的表格数据后,使用luckysheet初始化,或者更新已有的luckysheet工作簿
            const data = exportJson.sheets?.map(it => ({
                ...it,
                defaultColWidth: defaultWidth || 300,
            }))
            // 注:luckysheet需要引入依赖包和初始化表格容器才可以使用
            window.luckysheet?.create({
                container: 'luckysheet', // luckysheet is the container id
                showinfobar: false,
                data,
            })
            console.log(exportJson.sheets)
        },
        function(err) {
            console.log('Import failed. Is your fail a valid xlsx?')
        },
    )
}

这里我还加了一个默认列宽的参数,方便业务处理

exceljs

  1. 这时候需要用到这个插件了,将表格数据改造成excel文件格式,这样直接丢到上面写的方法中,就实现了tableData直接插入到excel中编辑了,传送门exceljs具体格式要求都有说明,这边就不做详细描述
const Excel = require('exceljs')

/**
 * 将表格数据回显到excel中
 * @param {*} header 表格头部数组
 * @param {*} tableData 表格数据
 * @param {*} defaultWidth 默认列宽
 */
export const tableToExcel = async (header, tableData, defaultWidth) => {
    // 创建工作簿
    const workbook = new Excel.Workbook()
    // 添加工作表
    const worksheet = workbook.addWorksheet('Sheet1')
    // 添加列标题并定义列键
    worksheet.columns = [...header]
    // 添加多行数据
    worksheet.addRows([...tableData])
    // 写入 buffer
    const buffer = await workbook.xlsx.writeBuffer()
    const file = new File([buffer], 'xxx.xlsx')
    transformFileToLucky(file, defaultWidth)
}

这时候就完成了tableData数据到excel编辑器的操作,在做相应操作之后,就需要将编辑后的数据再传给我们的导入接口,进行数据导入。

生成file文件

这里呢还是需要用到这个插件exceljs来处理,这里就比较麻烦一点,需要处理每一个sheet的样式格式啥的,我也是根据官网提供的栗子,以及借鉴了lishy97博主的使用exceljs导出luckysheet表格进行了兼容处理

/**
 * 获取excel文件对象
 * @param {*} luckysheet luckyspeet的data数据
 * @returns 返回传入接口的file对象
 */
export const getExcelFile = async luckysheet => {
    // 获取excel表数据
    const luckysheetData = luckysheet.getAllSheets()
    // 1.创建工作簿,可以为工作簿添加属性
    const workbook = new Excel.Workbook()
    // 2.创建表格,第二个参数可以配置创建什么样的工作表
    luckysheetData.forEach(function(table) {
        if (table.data.length === 0) return true
        const worksheet = workbook.addWorksheet(table.name)
        const merge = (table.config && table.config.merge) || {}
        const borderInfo = (table.config && table.config.borderInfo) || {}
        // 3.设置单元格合并,设置单元格边框,设置单元格样式,设置值,导出图片
        setStyleAndValue(table.data, worksheet)
        setMerge(merge, worksheet)
        setBorder(borderInfo, worksheet)
        setImages(table.images, worksheet, workbook)
        return true
    })
    // 4.写入 buffer
    const data = await workbook.xlsx.writeBuffer()
    const file = new File([data], 'xxx.xlsx')
    return file
}

这些代码我都放到了gitee仓库中,若是大家想看的话也可以自行下载查看传送门 基于luckysheet,实现表格编辑,文件处理后,我把组件封装成了一个vue插件

将拿到的file对象传入导入接口那么编辑完直接导入的功能就实现了。

扩展一下

以上实现了tableData转file,file导入excel插件,excel编辑器内容转file。由于那时候我已经有封装成插件的想法了,于是乎我就再写了一个导出功能。将excel中的内容导出下载

import FileSaver from 'file-saver'


/**
 * 下载excel文件
 * @param {*} luckysheet luckyspeet的data数据
 * @param {*} filename 下载名称
 */
export const exportExcel = async (luckysheet, filename) => {
    const luckysheetData = luckysheet.getAllSheets()
    // 1.创建工作簿,可以为工作簿添加属性
    const workbook = new Excel.Workbook()
    // 2.创建表格,第二个参数可以配置创建什么样的工作表
    luckysheetData.forEach(function(table) {
        if (table.data.length === 0) return true
        const worksheet = workbook.addWorksheet(table.name)
        const merge = (table.config && table.config.merge) || {}
        const borderInfo = (table.config && table.config.borderInfo) || {}
        // 3.设置单元格合并,设置单元格边框,设置单元格样式,设置值,导出图片
        setStyleAndValue(table.data, worksheet)
        setMerge(merge, worksheet)
        setBorder(borderInfo, worksheet)
        setImages(table.images, worksheet, workbook)
        return true
    })

    // 4.写入 buffer
    const data = await workbook.xlsx.writeBuffer()
    const blob = new Blob([data], {
        type: 'application/vnd.ms-excel;charset=utf-8',
    })
    FileSaver.saveAs(blob, `${filename}.xlsx`)
}

这里呢用到了file-saver这个插件做辅助。其实呢这个函数写的好点就应该分成两个方法,第一个是luckysheet的数据转buffer格式,(这一块与上面的获取file是一样的,写到后面我才发现,哈哈哈,后续再改一下);第二个就是文件导出,只要传入file格式文件,就可以导出。

打包成插件发到npm

传送门vue-lucky-excel,打包发布过程这边就不详细描述了,网上教程有非常多。我呢参照了这篇,这也是我第一次自己写插件,也是大致懂了npm发包的一个过程。

基于luckysheet,实现表格编辑,文件处理后,我把组件封装成了一个vue插件

总结

写这个主要是因为实现这些功能需要用到挺多插件的,就有了能不能装一个然后所有写好的功能就能用了的想法。目前这个插件用于vue,但是想法局限了。由于我加了一个vue组件一起封装,这就导致只能用在vue中,其实完全可以将js进行封装,因为这些js与框架无关,这样的话以后若是想在不同框架中使用也是没有问题的。后续我会持续优化的,电子表格后续可以玩的花样有很多,我想随着我们项目版本的迭代,这个插件也会添加更多的功能,让我们拭目以待。

大家有什么建议可以在评论区留言,欢迎大家可以一起来探讨。

参考

使用exceljs导出luckysheet表格 --lishy97

转载自:https://juejin.cn/post/7257518510523629629
评论
请登录