导出 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
首先要明确的两个概念是 workbook
和 worksheet
, 这两个对象分别对应了整个文件(工作簿)和一个文件中的一个表格(工作表)。
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 通过三种方法写入数据,这两种方法均会对数字、字符串、 null
和 undefined
、日期等类型进行自动解析:
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>