前端生成导出Excel


项目需求,需要在前端生成excel,后端仅返回数据。一开始我觉得前端是不能做这种读写文件的事情,然后去github上找了找,发现前端库也越来越强大了。目前github上前端操作excel的包就是 sheetjs了,也就是 js-xlsx,达到了22K多start,功能十分强大,关于sheetjs有个社区版本,可以导入导出excel,但不支持单元格合并背景色字体等这些功能。它还有个pro版,也就是收费版本,收费版对于单元格的样式设置则没有限制。不过本着开源精神 (主要还是穷….) ,对于这种要收费的包我只能果断放弃了,然后在npm的仓库中,在谷歌上搜啊找啊,发现另一个免费的excel包 xlsx-populate。它不仅免费,而且在API的使用上也比 sheetjs 要简单的多。不过本着学习的态度,对于 sheetjs 的社区版的使用,我也会放使用demo,毕竟先踩了它的坑。

js-xlsx

1.项目根目录安装

npm install xlsx

2.前端页面导入

import XLSX from 'xlsx';

3.导出excel

  // 表头
headers : {
        A1: {v: '2019年学生成绩表'},
        A3: { v: '编号' },
        B3: { v: '姓名' },
        C3: { v: '年龄' },
        D3: { v: '邮箱' }
      },
 // 数据     
data : {
        A4: { v:'100' },
        B4: { v:'张三' },
        C4: { v:'28' },
        D4: { v:'sanzhang@outlook.com' },

        A5: { v:'200' },
        B5: { v:'李四' },
        C5: { v:'26' },
        D5: { v:'sili@sina.com' }
      }
// 按钮
<Button type="primary" danger onClick={e => this.exportExcel(this.state.headers,this.state.data)}>
              导出Excel
</Button>


 // 导出excel点击事件
  // headers  表头
  // data     数据
  // fileName 文件名
  exportExcel = (headers, data, fileName = '请假记录表.xlsx') => {

    // 合并 headers 和 data
    const output = Object.assign({}, headers, data);
    // 获取所有单元格的位置
    const outputPos = Object.keys(output);
    // 计算出范围 ,["A1",..., "H2"]
    const ref = `${outputPos[0]}:${outputPos[outputPos.length - 1]}`;

    // 构建 workbook 对象
    const wb = {
      SheetNames: ['mySheet1','mySheet2'],
      Sheets: {
        mySheet1: Object.assign(
          {},
          output,
          {
            '!ref': ref,
            // 列宽度
            '!cols': [{ wpx: 65 }, { wpx: 100 }, { wpx: 200 }, { wpx: 80 }],
            // 合并单元格 0到1行,0到3列合并
            '!merges': [{
              s: { // s开始
                c: 0, // 开始列
                r: 0  // 开始行
              },
              e: { // e结束
                c: 3, // 结束列
                r: 1   // 结束行
              }
            }]
          },
        ),
        mySheet2: Object.assign(
          {},
          output,
          {
            '!ref': ref,
            '!cols': [{ wpx: 65 }, { wpx: 100 }, { wpx: 200 }, { wpx: 80 }],
            // 合并单元格
            '!merges': [{
              s: { // s开始
                c: 0, // 开始列
                r: 0  // 开始行
              },
              e: { // e结束
                c: 3, // 结束列
                r: 1   // 结束行
              }
            }]
          },
        )
      },
    };

    // 导出 Excel
    XLSX.writeFile(wb, fileName);
  };

4.导出结果

xlsx-populate

1.项目根目录安装

npm install xlsx-populate

2.前端页面导入

import XlsxPopulate from 'xlsx-populate';

3.导出excel

<Button type="primary" style={{marginLeft:'20px'}} onClick={e => this.exportXlsxPopulate()}>
              导出Excel2
 </Button>

  exportXlsxPopulate = () => {
    XlsxPopulate.fromBlankAsync()
      .then(workbook => {
        // Modify the workbook.
        // 第一个sheet页
        let wb = workbook.sheet("Sheet1");
        // 设置A列宽
        wb.column("A").width(40);
        // 设置第一行高
        wb.row(1).height(50);
        // 标题合并单元格  A列到D列,1行到2行合并
        wb.range("A1:D2").merged(true)
          .value("月考成绩\n2019年12月")
          .style("verticalAlignment", "center")//水平居中
          .style("horizontalAlignment", "center")//垂直居中
          .style("wrapText", true) //自动换行
          .style("border",true);
        // 表头
        wb.cell("A3")
          .value("姓名")
          .style("border",true)
          .style("verticalAlignment", "center")//水平居中
          .style("horizontalAlignment", "center");//垂直居中;

        wb.cell("B3")
          .value("语文")
          .style("border",true)
          .style("verticalAlignment", "center")//水平居中
          .style("horizontalAlignment", "center");//垂直居中;


        wb.cell("C3")
          .value("数学")
          .style("border",true)
          .style("verticalAlignment", "center")//水平居中
          .style("horizontalAlignment", "center");//垂直居中;

        wb.cell("D3")
          .value("英语")
          .style("border",true)
          .style("verticalAlignment", "center")//水平居中
          .style("horizontalAlignment", "center");//垂直居中;

        // 数据
        // 张三
        wb.cell("A4")
          .value("张三")
          .style("border",true)
          .style("verticalAlignment", "center")//水平居中
          .style("horizontalAlignment", "center");//垂直居中;

        wb.cell("B4")
          .value("84")
          .style("border",true)
          .style("verticalAlignment", "center")//水平居中
          .style("horizontalAlignment", "center");//垂直居中;


        wb.cell("C4")
          .value("88")
          .style("border",true)
          .style("verticalAlignment", "center")//水平居中
          .style("horizontalAlignment", "center");//垂直居中;

        wb.cell("D4")
          .value("92")
          .style("border",true)
          .style("verticalAlignment", "center")//水平居中
          .style("horizontalAlignment", "center");//垂直居中;

        // 李四
        wb.cell("A5")
          .value("李四")
          .style("border",true)
          .style("verticalAlignment", "center")//水平居中
          .style("horizontalAlignment", "center");//垂直居中;

        wb.cell("B5")
          .value("77")
          .style("border",true)
          .style("verticalAlignment", "center")//水平居中
          .style("horizontalAlignment", "center");//垂直居中;


        wb.cell("C5")
          .value("98")
          .style("border",true)
          .style("verticalAlignment", "center")//水平居中
          .style("horizontalAlignment", "center");//垂直居中;

        wb.cell("D5")
          .value("87")
          .style("border",true)
          .style("verticalAlignment", "center")//水平居中
          .style("horizontalAlignment", "center");//垂直居中;

        // Write to file.
        workbook.outputAsync().then(function(blob) {
          if (window.navigator && window.navigator.msSaveOrOpenBlob) {
            // If IE, you must uses a different method.
            window.navigator.msSaveOrOpenBlob(blob,  'test.xlsx');
          } else {
            let url = window.URL.createObjectURL(blob);
            let a = document.createElement('a');
            document.body.appendChild(a);
            a.href = url;
            a.download = 'test.xlsx';
            a.click();
            window.URL.revokeObjectURL(url);
            document.body.removeChild(a);
          }
        })
      });
  };

4.导出结果

更多样式属性的设置,可看官方文档。对于导出上面的例子简单明了,常规操作,下面来点不一样的

解析excel

// 从一个路径读取文件
XlsxPopulate.fromFileAsync("./Book1.xlsx")
    .then(workbook => {
        const value = workbook.sheet("Sheet1").cell("A1").value();
        console.log(value);
    });

// 从data中获取文件,data可以是blob ,buffer
  XlsxPopulate.fromDataAsync()

单元格设置为富文本

const RichText = require('xlsx-Populate').RichText;
const cell = workbook.sheet(0).cell('A1');
cell.value(new RichText());

cell.value()
    .add('hello ', { italic: true, bold: true })
    .add('world!', { fontColor: 'FF0000' });

单元格添加超链接

cell.value("Link Text")
    .style({ fontColor: "0563c1", underline: true })
    .hyperlink("http://example.com");

获取单元格背景

const XlsxPopulate = require('xlsx-populate');
XlsxPopulate.fromFileAsync("./Book1.xlsx")
    .then(workbook => {
        const background = workbook.sheet("Sheet1").cell("A1").style("fill");
        console.log(background);
    });

Author: 顺坚
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source 顺坚 !
评论
 Previous
分布式事务 分布式事务
在分布式、微服务大行其道的今天,分布式系统成为了标配。而说到使用分布式,或者拆分微服务的好处,你肯定能想到一大堆。既然有了分布式系统,那不可避免的就会用到分布式事务,这也是面试过程中经常会问的。暂不说你有没有真正使用过分布式事务,起码得对分
2020-08-16
Next 
MQL5学习笔记 MQL5学习笔记
最近在学习MQL5,MetaQuotes Language 5(MQL5)是一种面向对象的高水平的程序语言,它用来自动录入交易战略,为金融市场的各种分析定制智能指标。它不仅允许录入各种智能系统,更致力于实践操作,还能建立专属的图表工具帮您制
2020-07-18
  TOC