• 【js-xlsx和file-saver插件】前端导出数据到excel


      最近在做项目,前端进行处理数据,导出excel中,还是遇到不少问题,这里将其进行总结一下,博主是vue框架开发,借用file-saver和xlsx插件进行导出excel,我们来看下代码和效果。地址链接如下:https://www.npmjs.com/package/js-xlsx

      博主自己封装了一个方法xlsx.js,然后在vue中进行调用就行,如下:

    import fs from 'file-saver'
    import XLSX from 'xlsx'
    export default (json, fields, filename = '测试数据.xlsx') => {
    
        json.forEach(item => {
            for (let i in item) {
                if (fields.hasOwnProperty(i)) {
                    item[fields[i]] = item[i];
                }
                delete item[i]; //删除原先的对象属性
            }
        })
    
        let sheetName = filename //excel的文件名称
        let wb = XLSX.utils.book_new()  //工作簿对象包含一SheetNames数组,以及一个表对象映射表名称到表对象。XLSX.utils.book_new实用函数创建一个新的工作簿对象。
        let ws = XLSX.utils.json_to_sheet(json, { header: Object.values(fields) }) //将JS对象数组转换为工作表。
        wb.SheetNames.push(sheetName)
        wb.Sheets[sheetName] = ws
        const defaultCellStyle = { font: { name: "Verdana", sz: 13, color: "FF00FF88" }, fill: { fgColor: { rgb: "FFFFAA00" } } };//设置表格的样式
        let wopts = { bookType: 'xlsx', bookSST: false, type: 'binary', cellStyles: true, defaultCellStyle: defaultCellStyle, showGridLines: false }  //写入的样式
        let wbout = XLSX.write(wb, wopts)
        let blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' })
        fs.saveAs(blob, filename + '.xlsx')
    }
    
    const s2ab = s => {
        if (typeof ArrayBuffer !== 'undefined') {
            var buf = new ArrayBuffer(s.length)
            var view = new Uint8Array(buf)
            for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff
            return buf
        } else {
            var buf = new Array(s.length);
            for (var i = 0; i != s.length; ++i) buf[i] = s.charCodeAt(i) & 0xFF;
            return buf;
        }
    }

     调用当时如下,现在vue种引入该js文件,如下:

    import xlsx from "../../utils/xlsx.js";

    然后我们开始调用该方法,如下:

         /**
             * 导出到excel
             **/
            exportToExcel() {
                let fields = {
                    test1:"测试1",
                    test2:"测试2"
                };
                this.getHeadMapList.forEach(item => {
                    fields['_' +item.key] = item.value; //动态生成的头
                });
                fields.totalCommission = "奖励总数"
                //此处有vue大坑,不能直接使用xlsx(this.getComputedData),必须先转一下
                let data = JSON.parse(JSON.stringify(this.getComputedData));
           xlsx(data, fields,
    "奖励汇总列表"); },

      此处有两处大坑,一个是data不能直接使用this.getBuildData ,而要将其转换一下,原因是this.getBuildData是计算

    出来的,vue里面会自动更改它的值,这个bug找了好久才搞定,心塞。

     getComputedData() {
                let itemData = { };
                let arr = []
                this.dataList.map(item => {
                    this.formDataFitTable(
                        item.mapPrdTypeCommission,
                        this.getHeadMapList
                    ).map(v => {
                        itemData['_' + v.key] = v.value;
                    });
                    itemData.sid = item.sid;
                    itemData.yearMonth = item.yearMonth;
                    itemData.totalCommission = item.totalCommission;
                    arr.push(itemData);
                    itemData = { }; //注意要将其清空,然后再重新遍历
                });
                return arr;
            }

      第二个问题是,插入头部的时候,会存在顺序问题,比如业务要求,我就要将测试1放在excel的第一列里面,而实际上,

      对象是无序的,如果对象中单纯只包含数字类型的属性,或者字母类型的属性,是没有问题,而如果对象种既包含数字和字母

    的属性,那么对象就会优先将数字排在最前面。先看下导出结果如下:

      原本我是想将one这一列,放在第一列的位置上,然而结果却是排在最后面,当然因为我的数据格式里面就是既有数字类型,

    又有字母类型的,看下数据格式:

    {
      "test1":"测试1",
      "test2":"测试2",
       1:“测试3”,
       2:"测试4" ,
       3:“测试5”,
       4:"测试6" , 
       5:“测试7”,
       6:"测试8" ,
       7:“测试9”,
       8:"测试10" , 
       9:“测试11”,
       10:"测试12" , 
       11:“测试13”,
       12:"测试14" , 
       13:“测试15”,
       14:"测试16" ,         
    }

    那么导出的结果就会是如下所示:

    那么如何解决呢,其实只要将数字变为字符类型的就行了,上面代码也可以看出,加一个_就行了。

     2:拼接数据数组,如何导出呢?

      首先先看下效果,如下所示:这里数据虽然都打上了码,不过应该能明白博主的意思,显然这不是我们要的效果

    那么我们怎么解决呢?博主这里想到了一个比较笨的方法,欢迎大家指教,就是将其key值变为跟前面几列的相同,如下数据格式:

    exportToExcel() {
                let field = {
                    test1: "测试1",
                    test2: "测试2",
                    test3: "测试3",
                    test4: "测试4"
                };
                let r = this.requestData({
                    pageIndex: null,
                    pageSize: null,
                    isNotPaging: true
                });
                this.dispatchDataList(r).then(data => {
                    if (data) {
                        let data1= data.data1;
                        let data2 = data.data2;
                        let arry = [
                            {
                                test1:"",
                                test2:"",
                                test3:"",
                                test4:""
                            },
                            {
                                test1:"总状态",
                                test2:"总次数",
                                test3:"总数量",
                                test4:"总奖励"
                            }
                        ];
                        if(data2){
                            data2.forEach(item=>{
                                arry.push({
                                    test1:item.type,
                                    test2:item.rewardCount,
                                    test3:item.totalQuality,
                                    test3:item.totalCommission
                                })
                            })
                             xlsx( data1.concat(arry), field,"测试数据工作簿" );  
                        }else{
                             this.showTips("warning", "无数据,请重新查询!")
                        } 
                    }
                });
            },

      方法比较笨,但是效果是没问题的,有好的方法,欢迎大家指正。其实就是相当于,将其变为某一行数据格式

    插入到第一个数组里面,进行遍历第一个插入空的,是希望能够跟第一个数组隔开,转换之后效果如下:

    好啦,前端导入excel差不多就这么多,有好的方法欢迎大家给我留言!


     作者:婷风

     出处:http://www.cnblogs.com/jtjds/p/8892510.html 

     如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意 

    转载文章之后必须在 文章页面明显位置给出作者和原文连接否则保留追究法律责任的权利。

      

  • 相关阅读:
    UOJ309 UNR #2 排兵布阵
    BZOJ4860: [Beijing2017]树的难题
    CQOI2017 部分题解
    SDOI2017 Round1 Day2 题解
    记SCOI2017
    BZOJ3810: [Coci2015]Stanovi
    BZOJ4785: [Zjoi2017]树状数组
    「ZJOI2007」「LuoguP1169」棋盘制作(并查集
    「LuoguP4147」 玉蟾宫(并查集
    「LuoguP1402」 酒店之王(最大流
  • 原文地址:https://www.cnblogs.com/jtjds/p/8892510.html
Copyright © 2020-2023  润新知