JavaScript 导出表格

导出 CSV

JavaScript 导出 CSV 比较简单,只需要根据 CSV 的格式进行逗号分隔和换行,最后将文本保存成 CSV 文件即可。
需要注意的是,Excel 默认使用 ANSI 编码来打开 CSV 文件,如果 CSV 文件使用 UTF-8 编码,使用 Excel 打开就会乱码,解决方法是使用 Excel 中 数据 - 导入自文件 向导来导入 UTF-8 编码的 CSV 文件,这样就可以正常显示 Unicode 字符了。但这相比直接打开麻烦了很多,另一个办法是将 CSV 文件保存成 UTF-8 BOM 编码,这样 Excel 就会以 UTF-8 编码读取文件,不会出现乱码了。

BOM (Byte Order Mark) 是一段特定的十六进制序列,在 UTF-16 和 UTF-32 中用来标识该字节流的字节序,是高位在前还是低位在前,在 UTF-8 中 BOM 一般用来标识文件采用 UTF-8 编码,但并不是必要的。

UTF-8 的 BOM 的十六进制表示为 EF BB BF ,也可以用一个 Unicode 字符表示: U+FEFF 。所以我们只要在 CSV 文件开头加入 BOM 就可以将文件保存为 UTF-8 BOM 格式。可以直接在 Buffer 中先加入 \xEF\xBB\xBF 作为开头 ,也可以在字符串开头加入 \uFEFF 这个 Unicode 字符。

function writeCSV() {
    let csvContent = '\uFEFF';
    csvContent = csvContent.concat("布洛妮娅萌");
    fs.writeFileSync('konata.csv', csvContent);
}

导出 xls 和 xlsx

导出 xls 和 xlsx,肯定要使用库了,目前比较好用的是 SheetJS,它分为专业版和社区版,专业版主要增加了样式设置、插入图片图表的功能,据说价格很贵,一般情况下社区版足够使用了。社区版也叫做 js-xlsx,支持数据读取、解析处理、数据导出,同时支持浏览器端和 Node 端。

SheetJS 常用 API

workbook 和 worksheet

首先要明确的两个概念是 workbookworksheet , 这两个对象分别对应了整个文件(工作簿)和一个文件中的一个表格(工作表)。

workbook

workbook 有两种方式来获取:

  • 读取已有的文件,返回一个 workbook 对象。
  • 通过 XLSX.utils.book_new () 创建空白的 workbook 对象。

常用到的 workbook 的属性有两个:

  • Sheets :文件中的表格列表。

  • SheetNames :文件中的表格名列表,表现为数组。

    需要获取 workbook 中的某个表格时,可以这样获取:

let sheetname = workbook.SheetNames[0];
let worksheet = workbook.Sheets[sheetname];
worksheet

worksheet 对象代表文件中的一个表格,可以通过下标的形式访问表格中任意一小格的值:

worksheet['A1']

其返回值为一个对象,一般具有两个属性:

  • v :当前小格的值。
  • t :当前小格值的类型。

读取文件

SheetJS 通过两种方式读取文件内容:

  • XLSX.read (data, read_options) :读取 data 并解析。

  • XLSX.readFile (filename, read_options) :读取 filename 文件并解析。

    有关 read_options 的内容详见 read_options

写入数据

SheetJS 通过三种方法写入数据,这两种方法均会对数字、字符串、 nullundefined 、日期等类型进行自动解析:

  • XLSX.writeFile (workbook, filename [, write_options]) :按照 workbook 对象生成文件。若在浏览器端,会自动下载该文件。在 Node 端,会自动生成该文件并保存到本地

  • XLSX.writeFileAsync (filename, workbook, o, cb) : 按照 workbook 对象生成文件。当 o 执行完毕后,调用 cb 回调函数。

    有关 read_options 的内容详见 read_options

// XLSX.writeFile
// 第一个参数为一个 workbook 对象,第二个参数为所要生成文件的文件名
XLSX.writeFile(workbook, 'out.xlsb');

// XLSX.write
// 第一个参数为一个 workbook 对象,第二个参数是对生成文件格式的一些设置
// 在本例中,生成格式为 xlsx 的文件,编码为 base64
XLSX.write(workbook, {
    bookType: 'xlsx',
    bookSST: false,
    type: 'base64'
})
// 由于其不生成文件,而只是返回组成文件的数据,所以很适合一些需要通过异步请求来修改服务器上的文件等场景

转换数据格式

SheetJS 支持读取文件并把数据导出成任意格式,可通过以下几个 API 完成,传入的参数均是一个 worksheet 对象

  • XLSX.utils.sheet_to_csv (worksheet) :将表格数据转化为 CSV 格式。
  • XLSX.utils.sheet_to_txt (worksheet) :将表格数据转化为生成由 UTF-16 编码的 txt 格式。
  • XLSX.utils.sheet_to_html (worksheet) :将表格转化为 html 文件。
  • XLSX.utils.sheet_to_json (worksheet) : 将表格数据转化为 json 格式。

表格操作

  • XLSX.utils.aoa_to_sheet (Array [][]) :将二维数组转化为 worksheet 对象。
  • XLSX.utils.json_to_sheet (Object) :将 js 对象转化为 worksheet 对象。
  • XLSX.utils.table_to_sheet (HTML) :将 DOM 节点转化为 worksheet 对象(一般为 table 元素、 tr 元素和 th 元素)。
  • XLSX.utils.sheet_add_aoa (worksheet, Array [][]) :将二维数组中的数据添加到已有的 worksheet 中。
  • XLSX.utils.sheet_add_json (worksheet, Object) :将 js 对象中的数据添加到已有的 worksheet 中。
  • XLSX.utils.book_append_sheet (workbook, worksheet, sheetname) :将 worksheet 对象添加到 workbook 中,并命名为 sheetname

将网页中的 table 元素转换成 xlsx 并下载

引入 SheetJS:

<script lang="javascript" src="dist/xlsx.full.min.js"></script>

JavaScript:

function exportExcel() {
    const sheet = XLSX.utils.table_to_sheet(document.getElementsByTagName("table")[0]); // 将网页中第一个 table 元素转换为工作表对象
    let filename = document.getElementById("table-title").innerText; // 得到文件名
    openDownloadDialog(sheet2blob(sheet), filename + '.xlsx'); // 文件下载
}

// 将一个 sheet 转成最终的 excel 文件的 blob 对象,然后利用 URL.createObjectURL 下载
function sheet2blob(sheet, sheetName) {
    let workbook = {
        SheetNames: [sheetName],
        Sheets: {}
    };
    workbook.Sheets[sheetName] = sheet;
    // 生成 excel 的配置项
    const wopts = {
        bookType: 'xlsx', // 要生成的文件类型
        bookSST: false, // 是否生成 Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本 IOS 设备上有更好的兼容性
        type: 'binary'
    };
    let wbout = XLSX.write(workbook, wopts);
    let blob = new Blob([s2ab(wbout)], {
        type: "application/octet-stream"
    });

    // 字符串转 ArrayBuffer
    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;
    }
    return blob;
}

/**
 * 通用的打开下载对话框方法,没有测试过具体兼容性
 * @param url 下载地址,也可以是一个 blob 对象,必选
 * @param saveName 保存文件名,可选
 */
function openDownloadDialog(url, saveName) {
    if (typeof url == 'object' && url instanceof Blob)
        url = URL.createObjectURL(url); // 创建 blob 地址
    const aLink = document.createElement('a');
    aLink.href = url;
    aLink.download = saveName || ''; // HTML5 新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
    let 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);
}

HTML:

<button class="button is-link margin-btn" onclick="exportExcel()">
    导出 Excel
</button>

转载规则

《JavaScript 导出表格》Konata 采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。
  目录