js-xlsx

27,926 阅读18分钟

js-xlsx介绍

SheetJS出品的js-xlsx是一款非常方便的只需要纯JS即可读取和导出excel的工具库,功能强大,支持格式众多,支持xls、xlsx、ods(一种OpenOffice专有表格文件格式)等十几种格式。本文全部都是以xlsx格式为例。

官方工具类

其实上面这些代码都不需要我们手写,官方已经提供好了现成的工具类给我们使用,主要包括:

  • aoa_to_sheet: 这个工具类最强大也最实用了,将一个二维数组转成sheet,会自动处理number、string、boolean、date等类型数据;
  • table_to_sheet: 将一个table dom直接转成sheet,会自动识别colspan和rowspan并将其转成对应的单元格合并;
  • json_to_sheet: 将一个由对象组成的数组转成sheet

使用的技术

  1. xlsx 用于解析和编写各种电子表格。比如excel、csv、html文件
  2. xlsx-style 为xlsx库添加样式,比如字体颜色,大小,行宽等。但是只支持xlsx、xlsm、xlsb格式
  3. FileSaver.js 负责下载保存文件。对各种兼容性比较好,对跨域文件也有处理
  1. xlsx-style 只 支持16进制的ARGB颜色,比如:{ rgb: "FFFFAA00" }。注意这里是没有#号的。
  2. 添加背景色是使用fill的fgColor,而不是bgColor。这里需要驼峰编写。

js-xlsx使用

方式一

官网找到插件,dist目录下有很多个JS文件,一般情况下用xlsx.core.min.js就够了,xlsx.full.min.js则是包含了所有功能模块。

直接script标签引入即可

方式二

安装命令: npm install xlsx 引用:import XLSX from 'xlsx'

导出

1.操作dom导出

<!DOCTYPE html>
<html>

<head>
    <meta charset='utf-8'>
    <title>JS-XLSX Demo</title>
    <script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
</head>

<body>

    <table id="data-table" border="1" width="50%">
        <tbody>
            <tr>
                <td>编号</td>
                <td>名称</td>
                <td>价格</td>
                <td>日期</td>
            </tr>
            <tr>
                <td>1</td>
                <td>《Java架构师》</td>
                <td>¥78.5</td>
                <td>2018-10-11</td>
            </tr>
            <tr>
                <td>2</td>
                <td>《Python入门到精通》</td>
                <td>¥65.3</td>
                <td>2019-03-22</td>
            </tr>
            <tr>
                <td>3</td>
                <td>《JavaScript高级教程》</td>
                <td>¥89.4</td>
                <td>2017-04-13</td>
            </tr>
        </tbody>
    </table>

    <p>
        将上面表格的内容导出到Excel文件
    </p>
    <p>
        <button onclick="exportExcel()">导出Excel</button>
        <button onclick="noDomExportExcel()">不操作dom导出Excel</button>
    </p>

    <script type="text/javascript">

        function exportExcel() {
            // 获取表格的Dom对象
            var elt = document.getElementById('data-table');

            // 创建Excel工作簿,即一个Excel文件
            var wb = XLSX.utils.table_to_book(elt, {
                sheet: "SheetJS" // 工作表格名称
            });

            // 导出工作表
            return XLSX.writeFile(wb, 'SheetJSTableExport.xlsx');
        }

        function exportExcel2() {
            // 获取表格的Dom对象
            var elt1 = document.getElementById('xgszjcb-tb');
            var elt2 = document.getElementById('xqzjcbxtscb-tb');
            var elt3 = document.getElementById('xqzjcbdrb-tb');
            var elt4 = document.getElementById('xgszjsr-tb');

            // 创建虚拟workbook
            var wb = XLSX.utils.book_new();

            // 把数据生成sheet
            var sheet1 = XLSX.utils.table_to_sheet(elt1);
            var sheet2 = XLSX.utils.table_to_sheet(elt2);
            var sheet3 = XLSX.utils.table_to_sheet(elt3);
            var sheet4 = XLSX.utils.table_to_sheet(elt4);

            // 把sheet添加到workbook里
            XLSX.utils.book_append_sheet(wb, sheet1, "县区直接成本-合计");
            XLSX.utils.book_append_sheet(wb, sheet2, "县区直接成本-系统生成");
            XLSX.utils.book_append_sheet(wb, sheet3, "县区直接成本-导入");
            XLSX.utils.book_append_sheet(wb, sheet4, "县区直接收入-合计");

            // 导出工作表
            return XLSX.writeFile(wb, '县区公司.xlsx');
        }



        //不操作dom导出Excel
        function noDomExportExcel() {
            console.log('000000000');
            // 使用 XLSX.utils.aoa_to_sheet(excleData);
            const excleData = [
                ['周一', '周二', '周三', '周四', '周五'],
                ['语文', '数学', '历史', '政治', '英语'],
                ['数学', '数学', '政治', '英语', '英语'],
                ['政治', '英语', '历史', '政治', '数学'],
            ];


            // 使用 XLSX.utils.json_to_sheet(excleData);
            // const excleData = [
            //     { 周一: '语文', 周二: '数学', 周三: '历史', 周四: '政治', 周五: '英语' },
            //     { 周一: '数学', 周二: '数学', 周三: '政治', 周四: '英语', 周五: '英语' },
            //     { 周一: '政治', 周二: '英语', 周三: '历史', 周四: '政治', 周五: '数学' },
            // ];

            // 设置表格样式,!cols为列宽
            const options = {
                '!cols': [
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                ]
            };

            // 制作工作表的方式有很多种,以数组和对象为例
            // const worksheet: XLSX.WorkSheet = XLSX.utils.aoa_to_sheet(excleData);
            // const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(excleData);
            // const worksheet = XLSX.utils.json_to_sheet(excleData);
            const worksheet = XLSX.utils.aoa_to_sheet(excleData);

            // 使用指定的单元格作为起点插入数据,r:行, c:列,详情看官网文档
            // XLSX.utils.sheet_add_aoa(worksheet, [[“数学”,“语文”], [“政治”,“语文”], [“历史”,“政治”], ], {origin: {r: 2, c: 5}});
            worksheet['!cols'] = options['!cols'];  // 设置每列的列宽,10代表10个字符,注意中文占2个字符
            worksheet['!merges'] = [{ e: { c: 1, r: 1 }, s: { c: 0, r: 0 } }];
            console.log('workshe', worksheet['!merges']);



            // 新建一个工作簿
            // const workbook: XLSX.WorkBook = XLSX.utils.book_new();
            const workbook = XLSX.utils.book_new();//创建虚拟workbook
            console.log('workbook: ', workbook);

            /* 将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)*/
            XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
            /* 输出工作表, 由文件名决定的输出格式(book,xlsx文件名称)*/
            XLSX.writeFile(workbook, '排庭表.xlsx');
        }
    </script>
</body>

</html>

2.操作data导出

import XLSX from 'xlsx'

fnExport () {
        // 使用 XLSX.utils.aoa_to_sheet(excleData);
            const excleData = [
                ['周一', '周二', '周三', '周四', '周五'],
                ['语文', '数学', '历史', '政治', '英语'],
                ['数学', '数学', '政治', '英语', '英语'],
                ['政治', '英语', '历史', '政治', '数学'],
            ];


         // 使用 XLSX.utils.json_to_sheet(excleData);
            // const excleData = [
            //     { 周一: '语文', 周二: '数学', 周三: '历史', 周四: '政治', 周五: '英语' },
            //     { 周一: '数学', 周二: '数学', 周三: '政治', 周四: '英语', 周五: '英语' },
            //     { 周一: '政治', 周二: '英语', 周三: '历史', 周四: '政治', 周五: '数学' },
            // ];

       // 设置表格样式,!cols为列宽
            const options = {
                '!cols': [
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                ]
            };

    // 制作工作表的方式有很多种,以数组和对象为例
   // const worksheet = XLSX.utils.json_to_sheet(excleData);
      const worksheet = XLSX.utils.aoa_to_sheet(excleData);

      // 使用指定的单元格作为起点插入数据,r:行, c:列,详情看官网文档
            // XLSX.utils.sheet_add_aoa(worksheet, [[“数学”,“语文”], [“政治”,“语文”], [“历史”,“政治”], ], {origin: {r: 2, c: 5}});
      worksheet['!cols'] = options['!cols'];  // 设置每列的列宽,10代表10个字符,注意中文占2个字符
      worksheet['!merges'] = [{ e: { c: 1, r: 1 }, s: { c: 0, r: 0 } }];//合并单元格

      // 新建一个工作簿
      const workbook = XLSX.utils.book_new();//创建虚拟workbook
      /* 将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)*/
      XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
      /* 输出工作表, 由文件名决定的输出格式(book,xlsx文件名称)*/
       XLSX.writeFile(workbook, '排庭表.xlsx');

}

3.blob对象导出

将一个sheet转成最终的excel文件的blob对象,然后利用URL.createObjectURL下载

<!DOCTYPE html>
<html>

<head>
    <meta charset='utf-8'>
    <title>JS-XLSX Demo</title>
    <script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
    <script type="text/javascript" src='./libs/FileSaver.js'></script>
</head>
<body>
    <table id="data-table" border="1" width="50%">
        <tbody>
            <tr>
                <td>编号</td>
                <td>名称</td>
                <td>价格</td>
                <td>日期</td>
            </tr>
            <tr>
                <td>1</td>
                <td>《Java架构师》</td>
                <td>¥78.5</td>
                <td>2018-10-11</td>
            </tr>
            <tr>
                <td>2</td>
                <td>《Python入门到精通》</td>
                <td>¥65.3</td>
                <td>2019-03-22</td>
            </tr>
            <tr>
                <td>3</td>
                <td>《JavaScript高级教程》</td>
                <td>¥89.4</td>
                <td>2017-04-13</td>
            </tr>
        </tbody>
    </table>

    <p>
        将上面表格的内容导出到Excel文件
    </p>
   <p>
        <button onclick="blobUrlExportExcel()">blob对象借助URL导出Excel</button>
    </p>
    <script type="text/javascript">
        //将一个sheet转成最终的excel文件的blob对象
        function blobUrlExportExcel() {
            let table1 = document.querySelector("#data-table")
            let sheet = XLSX.utils.table_to_sheet(table1);//将一个table对象转换成一个sheet对象
            this.openDownloadDialog(sheet2blob(sheet), '下载.xlsx');
        }

        // 将一个sheet转成最终的excel文件的blob对象,然后利用URL.createObjectURL下载
        function sheet2blob(sheet, sheetName) {
            sheetName = sheetName || 'sheet1';
            var workbook = {
                SheetNames: [sheetName],
                Sheets: {}
            };
            workbook.Sheets[sheetName] = sheet; // 生成excel的配置项

            var wopts = {
                bookType: 'xlsx', // 要生成的文件类型
                bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
                type: 'binary'
            };
            var wbout = XLSX.write(workbook, wopts);
            var blob = new Blob([s2ab(wbout)], {
                type: "application/octet-stream"
            }); // 字符串转ArrayBuffer
            function s2ab(s) {
                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;
            }
            return blob;
        }

        function openDownloadDialog(url, saveName) {
            if (typeof url == 'object' && url instanceof Blob) {
                url = URL.createObjectURL(url); // 创建blob地址
            }
            var aLink = document.createElement('a');
            aLink.href = url;
            aLink.download = saveName || ''; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
            var event;
            if (window.MouseEvent) event = new MouseEvent('click');
            else {
                event = document.createEvent('MouseEvents');
                event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
            }
            aLink.dispatchEvent(event);
        }

    </script>
</body>

</html>

4.结合FileSaver插件导出

<!DOCTYPE html>
<html>

<head>
    <meta charset='utf-8'>
    <title>JS-XLSX Demo</title>
    <script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
    <script type="text/javascript" src='./libs/FileSaver.js'></script>
</head>
<body>
   <p>
        <button onclick="blobExportExcel()">结合FileSaver插件导出Excel</button>
    </p>
    <script type="text/javascript">
        function blobExportExcel() {
            //
            const excleData = [
                ['周一', '周二', '周三', '周四', '周五'],
                ['语文', '数学', '历史', '政治', '英语'],
                ['数学', '数学', '政治', '英语', '英语'],
                ['政治', '英语', '历史', '政治', '数学'],
            ];

            const options = {
                '!cols': [
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                ]
            };

            // 制作工作表的方式有很多种,以数组和对象为例
            const worksheet = XLSX.utils.aoa_to_sheet(excleData);
            worksheet['!cols'] = options['!cols'];
            // worksheet['!merges'] = [{ e: { c: 1, r: 1 }, s: { c: 0, r: 0 } }];

            // 新建一个工作簿
            const workbook = XLSX.utils.book_new();//创建虚拟workbook
            /* 将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)*/
            XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
            //
            let wbout = XLSX.write(workbook, { bookType: 'xlsx', type: 'binary' });
            saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), `测试.xlsx`);//saveAs方法存在于FileSaver插件中,从文件保存器中导入

        }

        function s2ab(s) {
            let buf = new ArrayBuffer(s.length);
            let view = new Uint8Array(buf);
            for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
            return buf;
        }
    </script>
</body>

</html>

导入

1.xlsx结合FileReader对象导入

  • 下载js-xlsx到dist复制出xlsx.full.min.js引入到页面中\
  • 然后通过FileReader对象读取文件利用js-xlsx转成json数据

FileReader共有4种读取方法:

  • readAsArrayBuffer(file) :将文件读取为ArrayBuffer
  • readAsBinaryString(file) :将文件读取为二进制字符串。
  • readAsDataURL(file) :将文件读取为Data URL
  • readAsText(file, [encoding]) :将文件读取为文本,encoding缺省值为'UTF-8'

eg:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
</head>

<body>
    <script>
        var wb;//读取完成的数据
        var rABS = false; //是否将文件读取为二进制字符串
        function importFile(obj) {//导入
            if (!obj.files) {
                return;
            }
            var f = obj.files[0];
            var reader = new FileReader();
            reader.onload = function (e) {
                var data = e.target.result;
                if (rABS) {
                    wb = XLSX.read(btoa(fixdata(data)), {//手动转化
                        type: 'base64'
                    });
                } else {
                    wb = XLSX.read(data, {

                        type: 'binary'//以二进制的方式读取
                    });
                }

                console.log('wb: ', wb);
                //wb.SheetNames[0]是获取Sheets中第一个Sheet的名字
                //wb.Sheets[Sheet名]获取第一个Sheet的数据
                // XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], { raw: false }); //以字符串形式读取。
                console.log('XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]): ', XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]));
                document.getElementById("demo").innerHTML = JSON.stringify(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]));

            };
            if (rABS) {
                reader.readAsArrayBuffer(f);
            } else {
                reader.readAsBinaryString(f);
            }
        }
        
        
   function fixdata(data) { //文件流转BinaryString
            var o = "",
                l = 0,
                w = 10240;
       for (; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)));
            o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)));
            return o;
        }
    </script>
    <div id="import">
        <p>导入模版</p>
        <p> 请选择要选择导入的模版文件</p>
        <input type="file" onchange="importFile(this)">
        <div id="demo"></div>
    </div>
</html>

xlsx-style 自定义导出样式

xlsx-style 为xlsx库添加样式,比如字体颜色,大小,行宽等。但是只支持xlsx、xlsm、xlsb格式

生成xlsx导出类。这里必须使用xlsx-style才能生成指定样式

 let wbout = xlsxStyle.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' });

完整代码

<script>
        //添加样式导出
        function sheetStyleExportExcel() {
            let sheet1data = [{ department: "行政部", count: 2 }, { department: "前端部", count: 2 }];
            let sheet2data = [{ name: "张三", do: "整理文件" }, { name: "李四", do: "打印" }];
            let sheet3data = [{ name: "张大人", do: "vue" }, { name: "李大人", do: "react" }];
            var sheet1 = XLSX.utils.json_to_sheet(sheet1data);//新建一个工作表
            var sheet2 = XLSX.utils.json_to_sheet(sheet2data);
            var sheet3 = XLSX.utils.json_to_sheet(sheet3data);
            var wb = XLSX.utils.book_new();//新建一个工作簿
            XLSX.utils.book_append_sheet(wb, sheet1, "部门统计");//将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)
            XLSX.utils.book_append_sheet(wb, sheet2, "行政部");
            XLSX.utils.book_append_sheet(wb, sheet3, "前端部");
            //
            // 设置表格样式,!cols为列宽
            const options = {
                '!cols': [//将第1,2,3,4,5 列的宽度设为100px
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                ]
            };
            sheet1['!cols'] = options['!cols'];  // 设置每列的列宽,10代表10个字符,注意中文占2个字符
            sheet1['!merges'] = [{ e: { c: 1, r: 1 }, s: { c: 0, r: 0 } }];//合并单元格
            //
            // var style = {
            //     // 表头样式
            //     hs: {
            //         font: { sz: 10, color: { rgb: "ff0000" }, bold: true },
            //         alignment: { horizontal: "center", vertical: "center", wrapText: true },
            //         fill: { bgColor: { indexed: 64 }, fgColor: { rgb: "FFFF00" } },
            //     },
            //     // 内容样式
            //     bs: {
            //         font: { sz: 11 },
            //         alignment: { horizontal: "center", vertical: "center", wrapText: true },
            //     },
            //     // 注释行样式
            //     ts: {
            //         font: { sz: 10, bold: true },
            //         alignment: { vertical: "center", wrapText: true },
            //         fill: { bgColor: { indexed: 64 }, fgColor: { rgb: "00B050" } }
            //     }
            // };

            //
            sheet2['A1'].s = {
                fill: {
                    fgColor: { rgb: 'FFA3F4B1' } // 添加背景色
                },
                font: {
                    sz: 18,                //18号字体
                    bold: true,             //加粗
                    color: {
                        rgb: 'FF4F81BD'  //字体颜色
                    },
                },
                alignment: {
                    horizontal: 'center'   //水平居中对其
                },
            }
            //
            let wbout = xlsxStyle.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' });
            // let wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' });
            saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), `测试.xlsx`);//saveAs方法存在于FileSaver插件中
        }
 </script>

    <script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
    <script type="text/javascript" src='./libs/FileSaver.js'></script>
    <script type="text/javascript" src='./libs/xlsxStyle.core.min.js'></script>
export(data, config, title = '导出文件名称') {
    const sheet = 'sheet1'
    const wb = XLSX.utils.book_new();
    const ws = XLSX.utils.aoa_to_sheet(data);
    XLSX.utils.book_append_sheet(wb, ws, sheet);
    // 合并单元格
    if (config ?.mergeCells ?.length) {
        let mergeObj = []
        config.mergeCells.forEach((element, i) => {
            let _obj = {
                s: {
                    c: element.col,
                    r: element.row
                },
                e: {
                    c: element.col + (element.colspan - 1),
                    r: element.row + (element.rowspan - 1)
                }
            }
            mergeObj.push(_obj)
        });
        XSU.mergeCellsByObj(wb, sheet, mergeObj);
    }
    XSU.setAlignmentHorizontalAll(wb, sheet, 'center');//垂直居中
    XSU.setAlignmentVerticalAll(wb, sheet, 'center');//水平居中

    XSU.setAlignmentWrapTextAll(wb, sheet, true)//自动换行
    XSU.setBorderDefaultAll(wb, sheet)//单元格默认边框

    const wbout = xlsxStyle.write(wb, { bookType: 'xlsx', type: 'binary' });
    saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), title + '.xlsx');
}

xlsx 导出多个sheet

方式1:

  • 借助FileSaver插件中的saveAs方法

eg:

<!DOCTYPE html>
<html>

<head>
    <meta charset='utf-8'>
    <title>JS-XLSX Demo</title>
    <script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
    <script type="text/javascript" src='./libs/FileSaver.js'></script>
</head>

<body>
  <button onclick="sheetExportExcel()">结合saveAs多sheet导出Excel</button>
  
   <script type="text/javascript">
    function sheetExportExcel() {
            let sheet1data = [{ department: "行政部", count: 2 }, { department: "前端部", count: 2 }];
            let sheet2data = [{ name: "张三", do: "整理文件" }, { name: "李四", do: "打印" }];
            let sheet3data = [{ name: "张大人", do: "vue" }, { name: "李大人", do: "react" }];
            var sheet1 = XLSX.utils.json_to_sheet(sheet1data);//新建一个工作表
            var sheet2 = XLSX.utils.json_to_sheet(sheet2data);
            var sheet3 = XLSX.utils.json_to_sheet(sheet3data);
            var wb = XLSX.utils.book_new();//新建一个工作簿
            XLSX.utils.book_append_sheet(wb, sheet1, "部门统计");//将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)
            XLSX.utils.book_append_sheet(wb, sheet2, "行政部");
            XLSX.utils.book_append_sheet(wb, sheet3, "前端部");
            //
            let wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' });
            saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), `测试.xlsx`);//saveAs方法存在于FileSaver插件中
        }

   </script>

</body>

</html>

方式2:

  • 把workbook转成blob
  • 利用a标签和createObjectURL实现下载功能

eg:

<!DOCTYPE html>
<html>

<head>
    <meta charset='utf-8'>
    <title>JS-XLSX Demo</title>
    <script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
    <script type="text/javascript" src='./libs/FileSaver.js'></script>
</head>

<body>
  <button onclick="sheetExportExcel()">多sheet导出Excel</button>
  
   <script type="text/javascript">

 function sheetExportExcel() {
            let sheet1data = [{ department: "行政部", count: 2 }, { department: "前端部", count: 2 }];
            let sheet2data = [{ name: "张三", do: "整理文件" }, { name: "李四", do: "打印" }];
            let sheet3data = [{ name: "张大人", do: "vue" }, { name: "李大人", do: "react" }];
            var sheet1 = XLSX.utils.json_to_sheet(sheet1data);//新建一个工作表
            var sheet2 = XLSX.utils.json_to_sheet(sheet2data);
            var sheet3 = XLSX.utils.json_to_sheet(sheet3data);
            var wb = XLSX.utils.book_new();//新建一个工作簿
            XLSX.utils.book_append_sheet(wb, sheet1, "部门统计");//将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)
            XLSX.utils.book_append_sheet(wb, sheet2, "行政部");
            XLSX.utils.book_append_sheet(wb, sheet3, "前端部");
            //
            const workbookBlob = workbook2blob(wb); // 将workbook装化成blob对象
            openDownloadDialog(workbookBlob, `部门统计.xlsx`);
        }
        
         // 将workbook装化成blob对象
        function workbook2blob(workbook) {
            // 生成excel的配置项
            var wopts = {
                // 要生成的文件类型
                bookType: "xlsx",
                // // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
                bookSST: false,
                type: "binary"
            };
            var wbout = XLSX.write(workbook, wopts);
            // 将字符串转ArrayBuffer
            function s2ab(s) {
                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;
            }
            var blob = new Blob([s2ab(wbout)], {
                type: "application/octet-stream"
            });
            return blob;
        }
        
        
        //将blob对象创建bloburl,然后用a标签实现弹出下载框
        function openDownloadDialog(url, saveName) {
            if (typeof url == 'object' && url instanceof Blob) {
                url = URL.createObjectURL(url); // 创建blob地址
            }
            var aLink = document.createElement('a');
            aLink.href = url;
            aLink.download = saveName || ''; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
            var event;
            if (window.MouseEvent) event = new MouseEvent('click');
            else {
                event = document.createEvent('MouseEvents');
                event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
            }
            aLink.dispatchEvent(event);
        }
   </script>

</body>

</html>

导出excel的逻辑

  • excel整个表格专业名词是workbook,里面每张表格是sheet

  • 页面引入xlsx的库,https://unpkg.com/xlsx/dist/xlsx.core.min.js

  • 把数据生成sheet,var sheet = XLSX.utils.json_to_sheet(jsonData),json_to_sheet是将由对象组成的数组转化成sheet,当然还有 aoa_to_sheet将一个二维数组转成sheet 和 table_to_sheet将table的dom直接转成sheet

  • 创建虚拟的workbook,var wb = XLSX.utils.book_new()

  • 把sheet添加到workbook里,XLSX.utils.book_append_sheet(wb, sheet, "这里是sheetName");

  • 把workbook转成blob

  • 利用a标签和createObjectURL实现下载功能 或 FileSaver插件的saveAs下载

完整的测试代码

1.export

<!DOCTYPE html>
<html>

<head>
    <meta charset='utf-8'>
    <title>JS-XLSX Demo</title>
    <script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
    <script type="text/javascript" src='./libs/FileSaver.js'></script>
</head>

<body>

    <table id="data-table" border="1" width="50%">
        <tbody>
            <tr>
                <td>编号</td>
                <td>名称</td>
                <td>价格</td>
                <td>日期</td>
            </tr>
            <tr>
                <td>1</td>
                <td>《Java架构师》</td>
                <td>¥78.5</td>
                <td>2018-10-11</td>
            </tr>
            <tr>
                <td>2</td>
                <td>《Python入门到精通》</td>
                <td>¥65.3</td>
                <td>2019-03-22</td>
            </tr>
            <tr>
                <td>3</td>
                <td>《JavaScript高级教程》</td>
                <td>¥89.4</td>
                <td>2017-04-13</td>
            </tr>
        </tbody>
    </table>

    <p>
        将上面表格的内容导出到Excel文件
    </p>
    <p>
        <button onclick="exportExcel()">导出Excel</button>
        <button onclick="noDomExportExcel()">不操作dom导出Excel</button>
        <button onclick="blobUrlExportExcel()">blob对象借助URL导出Excel</button>
        <button onclick="blobExportExcel()">blob对象导出Excel</button>
        <button onclick="sheetExportExcel()">结合saveAs多sheet导出Excel</button>
        <button onclick="sheetBlobExportExcel()">多sheet导出Excel</button>
    </p>

    <script type="text/javascript">

        function exportExcel() {
            // 获取表格的Dom对象
            var elt = document.getElementById('data-table');

            // 创建Excel工作簿,即一个Excel文件
            var wb = XLSX.utils.table_to_book(elt, {
                sheet: "SheetJS" // 工作表格名称
            });

            // 导出工作表
            return XLSX.writeFile(wb, 'SheetJSTableExport.xlsx');
        }

        function exportExcel2() {
            // 获取表格的Dom对象
            var elt1 = document.getElementById('xgszjcb-tb');
            var elt2 = document.getElementById('xqzjcbxtscb-tb');
            var elt3 = document.getElementById('xqzjcbdrb-tb');
            var elt4 = document.getElementById('xgszjsr-tb');

            // 创建虚拟workbook
            var wb = XLSX.utils.book_new();

            // 把数据生成sheet
            var sheet1 = XLSX.utils.table_to_sheet(elt1);
            var sheet2 = XLSX.utils.table_to_sheet(elt2);
            var sheet3 = XLSX.utils.table_to_sheet(elt3);
            var sheet4 = XLSX.utils.table_to_sheet(elt4);

            // 把sheet添加到workbook里
            XLSX.utils.book_append_sheet(wb, sheet1, "县区直接成本-合计");
            XLSX.utils.book_append_sheet(wb, sheet2, "县区直接成本-系统生成");
            XLSX.utils.book_append_sheet(wb, sheet3, "县区直接成本-导入");
            XLSX.utils.book_append_sheet(wb, sheet4, "县区直接收入-合计");

            // 导出工作表
            return XLSX.writeFile(wb, '县区公司.xlsx');
        }



        //不操作dom导出Excel
        function noDomExportExcel() {
            // 使用 XLSX.utils.aoa_to_sheet(excleData);
            const excleData = [
                ['周一', '周二', '周三', '周四', '周五'],
                ['语文', '数学', '历史', '政治', '英语'],
                ['数学', '数学', '政治', '英语', '英语'],
                ['政治', '英语', '历史', '政治', '数学'],
            ];


            // 使用 XLSX.utils.json_to_sheet(excleData);
            // const excleData = [
            //     { 周一: '语文', 周二: '数学', 周三: '历史', 周四: '政治', 周五: '英语' },
            //     { 周一: '数学', 周二: '数学', 周三: '政治', 周四: '英语', 周五: '英语' },
            //     { 周一: '政治', 周二: '英语', 周三: '历史', 周四: '政治', 周五: '数学' },
            // ];

            // 设置表格样式,!cols为列宽
            const options = {
                '!cols': [
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                ]
            };

            // 制作工作表的方式有很多种,以数组和对象为例
            // const worksheet: XLSX.WorkSheet = XLSX.utils.aoa_to_sheet(excleData);
            // const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(excleData);
            // const worksheet = XLSX.utils.json_to_sheet(excleData);
            const worksheet = XLSX.utils.aoa_to_sheet(excleData);

            // 使用指定的单元格作为起点插入数据,r:行, c:列,详情看官网文档
            // XLSX.utils.sheet_add_aoa(worksheet, [[“数学”,“语文”], [“政治”,“语文”], [“历史”,“政治”], ], {origin: {r: 2, c: 5}});
            worksheet['!cols'] = options['!cols'];  // 设置每列的列宽,10代表10个字符,注意中文占2个字符
            worksheet['!merges'] = [{ e: { c: 1, r: 1 }, s: { c: 0, r: 0 } }];
            console.log('workshe', worksheet['!merges']);



            // 新建一个工作簿
            // const workbook: XLSX.WorkBook = XLSX.utils.book_new();
            const workbook = XLSX.utils.book_new();//创建虚拟workbook
            console.log('workbook: ', workbook);

            /* 将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)*/
            XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
            /* 输出工作表, 由文件名决定的输出格式(book,xlsx文件名称)*/
            XLSX.writeFile(workbook, '排庭表.xlsx');
        }

        //将一个sheet转成最终的excel文件的blob对象
        function blobUrlExportExcel() {
            let table1 = document.querySelector("#data-table")
            let sheet = XLSX.utils.table_to_sheet(table1);//将一个table对象转换成一个sheet对象
            this.openDownloadDialog(sheet2blob(sheet), '下载.xlsx');
        }

        // 将一个sheet转成最终的excel文件的blob对象,然后利用URL.createObjectURL下载
        function sheet2blob(sheet, sheetName) {
            sheetName = sheetName || 'sheet1';
            var workbook = {
                SheetNames: [sheetName],
                Sheets: {}
            };
            workbook.Sheets[sheetName] = sheet; // 生成excel的配置项

            var wopts = {
                bookType: 'xlsx', // 要生成的文件类型
                bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
                type: 'binary'
            };
            var wbout = XLSX.write(workbook, wopts);
            var blob = new Blob([s2ab(wbout)], {
                type: "application/octet-stream"
            }); // 字符串转ArrayBuffer
            function s2ab(s) {
                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;
            }
            return blob;
        }

        //将blob对象创建bloburl,然后用a标签实现弹出下载框
        function openDownloadDialog(url, saveName) {
            if (typeof url == 'object' && url instanceof Blob) {
                url = URL.createObjectURL(url); // 创建blob地址
            }
            var aLink = document.createElement('a');
            aLink.href = url;
            aLink.download = saveName || ''; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
            var event;
            if (window.MouseEvent) event = new MouseEvent('click');
            else {
                event = document.createEvent('MouseEvents');
                event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
            }
            aLink.dispatchEvent(event);
        }


        //blobExportExcel
        function blobExportExcel() {
            //
            const excleData = [
                ['周一', '周二', '周三', '周四', '周五'],
                ['语文', '数学', '历史', '政治', '英语'],
                ['数学', '数学', '政治', '英语', '英语'],
                ['政治', '英语', '历史', '政治', '数学'],
            ];

            const options = {
                '!cols': [
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                    { wpx: 100 },
                ]
            };

            // 制作工作表的方式有很多种,以数组和对象为例
            const worksheet = XLSX.utils.aoa_to_sheet(excleData);
            worksheet['!cols'] = options['!cols'];
            // worksheet['!merges'] = [{ e: { c: 1, r: 1 }, s: { c: 0, r: 0 } }];

            // 新建一个工作簿
            const workbook = XLSX.utils.book_new();//创建虚拟workbook
            /* 将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)*/
            XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
            //
            let wbout = XLSX.write(workbook, { bookType: 'xlsx', type: 'binary' });
            saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), `测试.xlsx`);//saveAs方法存在于FileSaver插件中

        }

        function s2ab(s) {
            let buf = new ArrayBuffer(s.length);
            let view = new Uint8Array(buf);
            for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
            return buf;
        }


        //
        function sheetExportExcel() {
            let sheet1data = [{ department: "行政部", count: 2 }, { department: "前端部", count: 2 }];
            let sheet2data = [{ name: "张三", do: "整理文件" }, { name: "李四", do: "打印" }];
            let sheet3data = [{ name: "张大人", do: "vue" }, { name: "李大人", do: "react" }];
            var sheet1 = XLSX.utils.json_to_sheet(sheet1data);//新建一个工作表
            var sheet2 = XLSX.utils.json_to_sheet(sheet2data);
            var sheet3 = XLSX.utils.json_to_sheet(sheet3data);
            var wb = XLSX.utils.book_new();//新建一个工作簿
            XLSX.utils.book_append_sheet(wb, sheet1, "部门统计");//将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)
            XLSX.utils.book_append_sheet(wb, sheet2, "行政部");
            XLSX.utils.book_append_sheet(wb, sheet3, "前端部");
            //
            let wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' });
            saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), `测试.xlsx`);//saveAs方法存在于FileSaver插件中
        }



        function sheetBlobExportExcel() {
            let sheet1data = [{ department: "行政部", count: 2 }, { department: "前端部", count: 2 }];
            let sheet2data = [{ name: "张三", do: "整理文件" }, { name: "李四", do: "打印" }];
            let sheet3data = [{ name: "张大人", do: "vue" }, { name: "李大人", do: "react" }];
            var sheet1 = XLSX.utils.json_to_sheet(sheet1data);//新建一个工作表
            var sheet2 = XLSX.utils.json_to_sheet(sheet2data);
            var sheet3 = XLSX.utils.json_to_sheet(sheet3data);
            var wb = XLSX.utils.book_new();//新建一个工作簿
            XLSX.utils.book_append_sheet(wb, sheet1, "部门统计");//将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)
            XLSX.utils.book_append_sheet(wb, sheet2, "行政部");
            XLSX.utils.book_append_sheet(wb, sheet3, "前端部");
            //
            const workbookBlob = workbook2blob(wb); // 将workbook装化成blob对象
            openDownloadDialog(workbookBlob, `部门统计.xlsx`);
        }

        // 将workbook装化成blob对象
        function workbook2blob(workbook) {
            // 生成excel的配置项
            var wopts = {
                // 要生成的文件类型
                bookType: "xlsx",
                // // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
                bookSST: false,
                type: "binary"
            };
            var wbout = XLSX.write(workbook, wopts);
            // 将字符串转ArrayBuffer
            function s2ab(s) {
                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;
            }
            var blob = new Blob([s2ab(wbout)], {
                type: "application/octet-stream"
            });
            return blob;

        }
    </script>
</body>

</html>

2.import

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
    <script type="text/javascript" src='./libs/FileSaver.js'></script>
</head>

<body>
    <script>
        function importFile(obj) {//导入
            console.log('obj: ', obj);
            console.log('obj.files: ', obj.files);
            if (!obj.files) {
                return;
            }
            // alert(obj.files[0].name);文件名
            var f = obj.files[0];
            var reader = new FileReader();

            reader.onload = function (e) {
                var data = e.target.result;
                var wb = XLSX.read(data, {
                    type: 'binary' //以二进制的方式读取
                });

                var sheet0 = wb.Sheets[wb.SheetNames[0]];//sheet0代表excel表格中的第一页
                var str = XLSX.utils.sheet_to_json(sheet0);//利用接口实现转换。
                var templates = new Array();
                var str1 = obj.files[0].name;
                templates = str1.split(".");//将导入文件名去掉后缀
                console.log('JSON.stringify(str): ', JSON.stringify(str));
                // window.localStorage.setItem(templates[0], JSON.stringify(str))//存入localStorage 中

            }
            reader.readAsBinaryString(f);

        }



        // FileReader共有4种读取方法:
        // 1.readAsArrayBuffer(file) :将文件读取为ArrayBuffer。
        // 2.readAsBinaryString(file) :将文件读取为二进制字符串
        // 3.readAsDataURL(file) :将文件读取为Data URL
        // 4.readAsText(file, [encoding]) :将文件读取为文本,encoding缺省值为'UTF-8'

        var wb;//读取完成的数据
        var rABS = false; //是否将文件读取为二进制字符串

        function importFile1(obj) {//导入
            if (!obj.files) {
                return;
            }
            var f = obj.files[0];
            var reader = new FileReader();
            reader.onload = function (e) {
                var data = e.target.result;
                if (rABS) {
                    wb = XLSX.read(btoa(fixdata(data)), {//手动转化
                        type: 'base64'
                    });
                } else {
                    wb = XLSX.read(data, {

                        type: 'binary'//以二进制的方式读取
                    });
                }

                console.log('wb: ', wb);
                //wb.SheetNames[0]是获取Sheets中第一个Sheet的名字
                //wb.Sheets[Sheet名]获取第一个Sheet的数据
                // XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], { raw: false }); //以字符串形式读取。
                console.log('XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]): ', XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]));
                document.getElementById("demo").innerHTML = JSON.stringify(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]));

            };
            if (rABS) {
                reader.readAsArrayBuffer(f);
            } else {
                reader.readAsBinaryString(f);
            }
        }

        function fixdata(data) { //文件流转BinaryString
            var o = "",
                l = 0,
                w = 10240;
            for (; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)));
            o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)));
            return o;
        }


    </script>
    <div id="import">
        <p>导入模版</p>
        <p> 请选择要选择导入的模版文件</p>
        <input type="file" onchange="importFile(this)">
        <input type="file" onchange="importFile1(this)">


        <div id="demo"></div>
    </div>
</body>

</html>