前端使用xlsx、file-saver实现自定义excel格式导出(列宽、字体、边框、行高)

2 篇文章 1 订阅
2 篇文章 0 订阅

前端使用xlsx、file-saver实现excel导出

xlsx-style可以自定义表格样式

1.下载依赖

使用命令行下载所需要的依赖,会在在package.json文件内添加。

"dependencies": {
    "axios": "^0.19.2",
    "babel-polyfill": "^6.26.0",
    "element-ui": "^2.15.6",
    "file-saver": "^2.0.5",
    "pinyin-match": "^1.2.2",
    "print-js": "^1.6.0",
    "vue": "^2.5.2",
    "vue-router": "^3.0.1",
    "vuex": "^3.1.2",
    "xlsx": "^0.17.0",
    "xlsx-style": "^0.8.13"
  },

在这里插入图片描述

2.在需要导出excel的页面使用依赖

  import XLSX from "xlsx";
  import XLSXSTYLE from "xlsx-style";
  import FileSaver from "file-saver";

在这里插入图片描述

3.实现导出excel文件功能

3.1给需要导出的表格赋予id

<el-table size="mini" id="todaytable"
                  :header-cell-style="headerMerge"
                  :span-method="arraySpanMethod"
                  :cell-style="cellStyle"
                  ref="multipleTable"
                  :data="tableData"
                  border
                  stripe
                  style="width: 100%">

在这里插入图片描述

3.2按钮调用导出文件函数

                <el-button @click="handleDownload()">下载</el-button>

3.3函数实现导出功能

按照id定位到需要导出的表格

      handleDownload () {
        this.outputXLSX('文件名', '#todaytable', this);
      },
      outputXLSX (filename, selector, _this) {
        let ws = XLSX.utils.table_to_sheet(document.getElementById('todaytable'))
        //创建一个workbook对象
        let wb2 = XLSX.utils.book_new()
        //把worksheet对象添加进workbook对象,第三个参数是excel中sheet的名字
        XLSX.utils.book_append_sheet(wb2, ws, filename)
        this.setExlStyle(wb2['Sheets'][filename]); // 设置列宽 字号等
        this.addRangeBorder(wb2['Sheets'][filename]['!merges'],wb2['Sheets'][filename]) // 单元格合并
        let wb_out = XLSXSTYLE.write(wb2, { type: 'buffer'})
        try {
          FileSaver.saveAs(new Blob([wb_out], {
            type: 'application/octet-stream'
          }), filename+'.xlsx');   //filename.xlsx 为导出的文件名
        } catch (e) {
          console.log(e, wb_out) ;
        }
        return wb_out;
      },
      setExlStyle(data) {
        let borderAll = {  //单元格外侧框线
          top: {
            style: 'thin',
          },
          bottom: {
            style: 'thin'
          },
          left: {
            style: 'thin'
          },
          right: {
            style: 'thin'
          }
        };
        data['!cols'] = [];
        for (let key in data) {
        // 按照数值调整文件字体颜色,数值<0,字体变红。
          let col = '000000'
          if (data[key] instanceof Object) {
            if (data[key].v<0) {
              col = 'ff0000'
            } else {
              col = '000000'
            }
            data[key].s = {
              border: borderAll,
              alignment: {
                horizontal: 'center',   //水平居中对齐
                vertical:'center'
              },
              font:{
              // 自定义字体颜色
                color: {rgb: col},
                sz:11
              },
              bold:true,
              numFmt: 0
            }
            // 自定义列宽,每列都一样
            // data['!cols'].push({wpx: 80})
          }
        }
        // 自定义列宽, 每列不一样
        data['!cols'] = [{wpx: 40},{wpx: 100},{wpx: 85},{wpx: 85},{wpx: 85},{wpx: 85},{wpx: 85},
          {wpx: 85},{wpx: 85},{wpx: 85},{wpx: 85},{wpx: 85},{wpx: 85},{wpx: 85},{wpx: 85},{wpx: 85}
          ,{wpx: 85},{wpx: 85},{wpx: 85},{wpx: 85},{wpx: 85},{wpx: 85}];
        return data;
      },
      addRangeBorder (range, ws) {
        let cols = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
        range.forEach(item => {
          let style = {
            s: {
              border: {
                top: { style: 'thin' },
                left: { style: 'thin' },
                bottom: { style: 'thin' },
                right: { style: 'thin' }
              }
            }
          }
          // 处理合并行
          for (let i = item.s.c; i <= item.e.c; i++) {
            ws[`${cols[i]}${Number(item.e.r) + 1}`] = ws[`${cols[i]}${Number(item.e.r) + 1}`] || style
            // 处理合并列
            for (let k = item.s.r + 2; k <= item.e.r + 1; k++) {
              ws[cols[i] + k] = ws[cols[k] + item.e.r] || style
            }
          }
        })
        return ws;
      },

因为我的头部是三级而且有合并,导致导出的文件列会有错行或者合并单元格有错,可以输出每一列查看对应数值,自己重新赋值。
我的表头第3行数据会后退一列,使用下方函数进行重新赋值。
wb2[‘Sheets’][filename].D3 = wb2[‘Sheets’][filename].F3
意思是:让D列3行的数据等于F列3行的数据,就是把后一列的数据给前一列,表头就正确了。

有时候表头最后一列是加边框的空单元格,也可以使用上述方法重新赋值,让有边框的空单元格等于他后一列没有边框的空单元格。

      outputXLSX (filename, selector, _this) {
        let ws = XLSX.utils.table_to_sheet(document.getElementById('todaytable'))
        //创建一个workbook对象
        let wb2 = XLSX.utils.book_new()
        //把worksheet对象添加进workbook对象,第三个参数是excel中sheet的名字
        XLSX.utils.book_append_sheet(wb2, ws, filename)
        // 输出查看每列数值
        console.log(wb2['Sheets'][filename])
        // 表头重新赋值
        wb2['Sheets'][filename].D3 = wb2['Sheets'][filename].F3
        wb2['Sheets'][filename].E3 = wb2['Sheets'][filename].G3
        wb2['Sheets'][filename].F3 = wb2['Sheets'][filename].H3
        wb2['Sheets'][filename].G3 = wb2['Sheets'][filename].I3
        wb2['Sheets'][filename].H3 = wb2['Sheets'][filename].J3
        wb2['Sheets'][filename].I3 = wb2['Sheets'][filename].K3
        wb2['Sheets'][filename].J3 = wb2['Sheets'][filename].L3
        // 合并重新调整
        wb2['Sheets'][filename]['!merges'][1].e.c = 1
        wb2['Sheets'][filename]['!merges'][1].s.c = 0
        this.setExlStyle(wb2['Sheets'][filename]); // 设置列宽 字号等
        this.addRangeBorder(wb2['Sheets'][filename]['!merges'],wb2['Sheets'][filename])
        let wb_out = XLSXSTYLE.write(wb2, { type: 'buffer'})

        try {
          FileSaver.saveAs(new Blob([wb_out], {
            type: 'application/octet-stream'
          }), filename+'.xlsx');   //trade-publish.xlsx 为导出的文件名
        } catch (e) {
          console.log(e, wb_out) ;
        }
        return wb_out;
      },
调整行高

百度搜了好久,参考了各个大神的做法,最后参考这个文章的实现了
链接: https://blog.csdn.net/jililin123/article/details/126249198#comments_24348365

需要修改xlxs-style的内容

# 第一步 修改nod_modules 里面xlsx-style文件夹下面dist文件夹下的cpexcel.js文件
807: var cpt = cptable;

# 第二步 修改xlsx-style文件夹下面ods.js文件
10: return require('./' + 'xlsx').utils;
12: try { return require('./' + 'xlsx').utils; }

# 第三步 修改xlsx-style文件夹下面的xlsx.js文件 替换write_ws_xml_data以下方法
var DEF_PPI = 96, PPI = DEF_PPI;
function px2pt(px) { return px * 96 / PPI; }
function pt2px(pt) { return pt * PPI / 96; }
function write_ws_xml_data(ws, opts, idx, wb) {
 var o = [], r = [], range = safe_decode_range(ws['!ref']), cell, ref, rr = "", cols = [], R, C,rows = ws['!rows'];
 for(C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
 for(R = range.s.r; R <= range.e.r; ++R) {
   r = [];
   rr = encode_row(R);
   for(C = range.s.c; C <= range.e.c; ++C) {
     ref = cols[C] + rr;
     if(ws[ref] === undefined) continue;
     if((cell = write_ws_xml_cell(ws[ref], ref, ws, opts, idx, wb)) != null) r.push(cell);
   }
   if(r.length > 0){
  params = ({r:rr});
  if(rows && rows[R]) {
   row = rows[R];
   if(row.hidden) params.hidden = 1;
   height = -1;
   if (row.hpx) height = px2pt(row.hpx);
   else if (row.hpt) height = row.hpt;
   if (height > -1) { params.ht = height; params.customHeight = 1; }
   if (row.level) { params.outlineLevel = row.level; }
  }
  o[o.length] = (writextag('row', r.join(""), params));
 }
 }
if(rows) for(; R < rows.length; ++R) {
 if(rows && rows[R]) {
  params = ({r:R+1});
  row = rows[R];
  if(row.hidden) params.hidden = 1;
  height = -1;
  if (row.hpx) height = px2pt(row.hpx);
  else if (row.hpt) height = row.hpt;
  if (height > -1) { params.ht = height; params.customHeight = 1; }
  if (row.level) { params.outlineLevel = row.level; }
  o[o.length] = (writextag('row', "", params));
 }
}
 return o.join("");
}

在setExlStyle函数里增加设置行高的属性data[“!rows”]

		// 行高
        data["!rows"] = [{hpx: 40},{hpx: 40},{hpx: 40}]; 
        // 列宽
        data['!cols'] = [{wpx: 20},{wpx: 80},{wpx: 35},{wpx: 55},{wpx: 55},{wpx: 55},{wpx: 55},
          {wpx: 55},{wpx: 55},{wpx: 55},{wpx: 55},{wpx: 55},{wpx: 55},{wpx: 55},{wpx: 55},{wpx: 55}];
        return data;
调整背景色

用到属性fill的bgColor。
COLOR_SPEC 指设定颜色的对象,取值如下:
{ rgb: “FFFFAA00” } 十六进制ARGB值
{ theme: “1”} 主题颜色的整数索引,默认是0。
在这里插入图片描述

更多内容参考: https://www.imooc.com/article/305180

4.xlxs-style属性

单元格属性

在这里插入图片描述

单元格样式

在这里插入图片描述

  • 7
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
好的,针对您的问题,我可以给您一些思路和建议: 1. 首先,您需要安装 xlsxfile-saver 两个库。您可以使用 npm 进行安装,命令如下: ``` npm install xlsx file-saver --save ``` 2. 接下来,您需要将数据按照相同项进行合并。您可以使用 JavaScript 的 Array.reduce() 方法来实现。例如,假设您的数据如下: ``` const data = [ { name: 'Alice', age: 25, gender: 'female' }, { name: 'Bob', age: 30, gender: 'male' }, { name: 'Alice', age: 35, gender: 'female' }, { name: 'Bob', age: 40, gender: 'male' }, { name: 'Alice', age: 45, gender: 'female' } ]; ``` 您可以使用以下代码将数据按照姓名进行合并: ``` const mergedData = data.reduce((acc, cur) => { const key = cur.name; if (!acc[key]) { acc[key] = { name: key, age: cur.age, gender: cur.gender }; } else { acc[key].age += cur.age; } return acc; }, {}); ``` 最终,您会得到如下的合并后的数据: ``` { "Alice": { "name": "Alice", "age": 105, "gender": "female" }, "Bob": { "name": "Bob", "age": 70, "gender": "male" } } ``` 3. 最后,您可以使用 xlsxfile-saver 库将数据导出Excel 文件。具体步骤如下: - 将合并后的数据转换为 Excel 的工作簿对象: ``` const workbook = XLSX.utils.book_new(); const sheet = XLSX.utils.json_to_sheet(Object.values(mergedData)); XLSX.utils.book_append_sheet(workbook, sheet, 'Sheet1'); ``` - 将工作簿对象保存为 Excel 文件: ``` const buffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' }); const blob = new Blob([buffer], { type: 'application/octet-stream' }); saveAs(blob, 'data.xlsx'); ``` 其中,saveAs() 方法来自于 file-saver 库,用于将 Blob 对象保存为文件。 希望以上的思路和代码可以帮助到您。如果您有任何问题或疑问,请随时向我提出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值