最近在开发时候遇到了这样的一个需求:需要在前端通过解析Excel将Excel中的值进行回传填入。我想在实际的开发过程中,肯定大家也会遇到这样的需求,在这介绍一个比较不错的JS工具库:js-xlsx,及该库的简单使用方法。

1、js-xlsx简介

        js-xlsx是由SheetJs出品的纯JS即可实现读取和导出Excel的工具库,功能强大,使用方便,支持格式多,官方Git地址: https://github.com/SheetJS/js-xlsx

1.1、兼容性

1.2 使用方式

        支持直接使用标签进行引用:

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

         也支持CDN引用:

CDNURL
unpkgUNPKG - xlsxhttps://jsdelivr.com/package/npm/xlsxUNPKG - xlsx
jsDelivrxlsx CDN by jsDelivr - A CDN for npm and GitHub
CDNjsxlsx - Libraries - cdnjs - The #1 free and open source CDN built to make life easier for developers
packd

https://bundle.run/xlsx@latest?name=XLSX

        使用npm安装

$ npm install xlsx

        使用bower安装

$ bower install js-xlsx

2、读取excle文件

        读取excel主要是通过XLSX.read(data, {type: type});方法来实现,返回一个叫WorkBook的对象,type主要取值如下:

  • base64: 以base64方式读取;
  • binary: BinaryString格式(byte n is data.charCodeAt(n))
  • string: UTF8编码的字符串;
  • buffer: nodejs Buffer;
  • array: Uint8Array,8位无符号数组;
  • file: 文件的路径(仅nodejs下支持);

 2.1 读取本地文件

// 读取本地excel文件
function readWorkbookFromLocalFile(file, callback) {
	var reader = new FileReader();
	reader.readAsBinaryString(file);
	reader.onload = function(e) {
		var data = e.target.result;
		var workbook = XLSX.read(data, {type: 'binary'});
		if(callback) callback(workbook);
	};
}

2.2 读取workbook

        不处理合并单元格

function readWorkbook(workbook) {
        var sheetContent = []
        // 遍历每张表读取
        for (var sheet in workbook.Sheets) {
            if (workbook.Sheets.hasOwnProperty(sheet)) {
                fromTo = workbook.Sheets[sheet]['!ref'];
                sheetContent.push(XLSX.utils.sheet_to_json(workbook.Sheets[sheet]))
                // break; // 如果只取第一张表,就取消注释这行
            }
        }
        return sheetContent
}

        处理合并单元格

// 读取 excel文件
function outputWorkbook(workbook) {
	var sheetNames = workbook.SheetNames; // 工作表名称集合
	sheetNames.forEach(name => {
		var worksheet = workbook.Sheets[name]; // 只能通过工作表名称来获取指定工作表
		for(var key in worksheet) {
			// v是读取单元格的原始值
			console.log(key, key[0] === '!' ? worksheet[key] : worksheet[key].v);
		}
	});
}

        根据!ref确定excel的范围,再根据!merges确定单元格合并(如果有),最后输出整个table,比较麻烦,幸运的是,插件自身已经写好工具类XLSX.utils给我们直接使用,无需我们自己遍历,工具类输出主要包括如下:

        有些不常用,常用的主要是:

  •  XLSX.utils.sheet_to_csv:生成CSV格式
  • XLSX.utils.sheet_to_txt:生成纯文本格式
  • XLSX.utils.sheet_to_html:生成HTML格式
  • XLSX.utils.sheet_to_json:输出JSON格式

3、导出excel

3.1 手写代码实现

// 将一个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;
}

3.2 利用官方工具类

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

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

 3.3 处理单元格合并

var aoa = [
	['主要信息', null, null, '其它信息'], // 特别注意合并的地方后面预留2个null
	['姓名', '性别', '年龄', '注册时间'],
	['张三', '男', 18, new Date()],
	['李四', '女', 22, new Date()]
];
var sheet = XLSX.utils.aoa_to_sheet(aoa);
sheet['!merges'] = [
	// 设置A1-C1的单元格合并
	{s: {r: 0, c: 0}, e: {r: 0, c: 2}}
];
openDownloadDialog(sheet2blob(sheet), '单元格合并示例.xlsx');

4、样例 

        最后,上一段直接读取本地文件后返回Json格式的代码,方便进行参考

//读取本地Excel表格
function readWorkbookFromLocalFile(files) {
    var fileReader = new FileReader()
    fileReader.readAsBinaryString(files[0])
    return new Promise(function(resolve, reject) {
        fileReader.onload = function (ev) {
            try {
                var data = ev.target.result
                var workbook = XLSX.read(data, {
                    type: 'binary'
                }) // 以二进制流方式读取得到整份excel表格对象
                var fromTo = '';
                var sheetContent = []
                // 遍历每张表读取
                for (var sheet in workbook.Sheets) {
                    if (workbook.Sheets.hasOwnProperty(sheet)) {
                        fromTo = workbook.Sheets[sheet]['!ref'];
                        sheetContent.push(XLSX.utils.sheet_to_json(workbook.Sheets[sheet]))
                        // break; // 如果只取第一张表,就取消注释这行
                    }
                }
                respondBody = {
                    code: 100,
                    msg: '文件解析成功',
                    body: sheetContent
                }
                resolve(respondBody)
            } catch (e) {
                respondBody = {
                    code: 500,
                    msg: '文件类型不正确',
                    body: ''
                }
                reject(respondBody)
            }
        }
    })
}

tips:多看书,多总结,少写代码!

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐