xlsx导出excel功能封装
参考:
按需引入 xlsx 库,完全引入这个库的话还是挺大的
安装
sh
# npm
npm install xlsx
# yarn
yarn add xlsx
# pnpm
pnpm add xlsx
封装及使用
js
import { SSF, utils, writeFileXLSX } from 'xlsx'
function generateArray(table) {
const out = []
const rows = table.querySelectorAll('tr')
const ranges = []
for (let R = 0; R < rows.length; ++R) {
const outRow = []
const row = rows[R]
const columns = row.querySelectorAll('td')
for (let C = 0; C < columns.length; ++C) {
const cell = columns[C]
let colspan = cell.getAttribute('colspan')
let rowspan = cell.getAttribute('rowspan')
let cellValue = cell.textContent
if (cellValue !== '' && cellValue == +cellValue) cellValue = +cellValue
// Skip ranges
ranges.forEach((range) => {
if (
R >= range.s.r
&& R <= range.e.r
&& outRow.length >= range.s.c
&& outRow.length <= range.e.c
) {
for (let i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null)
}
})
// Handle Row Span
if (rowspan || colspan) {
rowspan = rowspan || 1
colspan = colspan || 1
ranges.push({
s: { r: R, c: outRow.length },
e: { r: R + rowspan - 1, c: outRow.length + colspan - 1 }
})
}
// Handle Value
outRow.push(cellValue !== '' ? cellValue : null)
// Handle Colspan
if (colspan) {
for (let k = 0; k < colspan - 1; ++k) outRow.push(null)
}
}
out.push(outRow)
}
return [out, ranges]
}
function datenum(v, date1904) {
if (date1904) v += 1462
const epoch = Date.parse(v)
return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000)
}
function sheet_from_array_of_arrays(data) {
const ws = {}
const range = { s: { c: 10000000, r: 10000000 }, e: { c: 0, r: 0 } }
for (let R = 0; R != data.length; ++R) {
for (let C = 0; C != data[R].length; ++C) {
if (range.s.r > R) range.s.r = R
if (range.s.c > C) range.s.c = C
if (range.e.r < R) range.e.r = R
if (range.e.c < C) range.e.c = C
const cell = { v: data[R][C] }
if (cell.v == null) continue
const cell_ref = utils.encode_cell({ c: C, r: R })
if (typeof cell.v === 'number') {
cell.t = 'n'
} else if (typeof cell.v === 'boolean') {
cell.t = 'b'
} else if (cell.v instanceof Date) {
cell.t = 'n'
cell.z = SSF._table[14]
cell.v = datenum(cell.v)
} else {
cell.t = 's'
}
ws[cell_ref] = cell
}
}
if (range.s.c < 10000000) ws['!ref'] = utils.encode_range(range)
return ws
}
function Workbook() {
if (!(this instanceof Workbook)) return new Workbook()
this.SheetNames = []
this.Sheets = {}
}
// function s2ab(s) {
// const buf = new ArrayBuffer(s.length)
// const view = new Uint8Array(buf)
// for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF
// return buf
// }
export function export_table_to_excel(id) {
const theTable = document.getElementById(id)
const oo = generateArray(theTable)
const ranges = oo[1]
/* original data */
const data = oo[0]
const ws_name = 'SheetJS'
const wb = new Workbook(),
ws = sheet_from_array_of_arrays(data)
/* add ranges to worksheet */
// ws['!cols'] = ['apple', 'banan'];
ws['!merges'] = ranges
/* add worksheet to workbook */
wb.SheetNames.push(ws_name)
wb.Sheets[ws_name] = ws
// var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' });
// saveAs(new Blob([s2ab(wbout)], { type: "application/octet-stream" }), "test.xlsx")
writeFileXLSX(wb, 'test.xlsx')
}
export function export_json_to_excel(th, jsonData, defaultTitle) {
/* original data */
const data = jsonData
data.unshift(th)
const ws_name = 'SheetJS'
const wb = new Workbook(),
ws = sheet_from_array_of_arrays(data)
/* 设置worksheet每列的最大宽度 */
const colWidth = data.map(row =>
row.map((val) => {
/* 先判断是否为null/undefined */
if (val == null) {
return { wch: 10 }
} else if (val.toString().charCodeAt(0) > 255) {
/* 再判断是否为中文 */
return { wch: val.toString().length * 2 }
} else {
return { wch: val.toString().length }
}
})
)
/* 以第一行为初始值 */
const result = colWidth[0]
for (let i = 1; i < colWidth.length; i++) {
for (let j = 0; j < colWidth[i].length; j++) {
if (result[j].wch < colWidth[i][j].wch) {
result[j].wch = colWidth[i][j].wch
}
}
}
ws['!cols'] = result
/* add worksheet to workbook */
wb.SheetNames.push(ws_name)
wb.Sheets[ws_name] = ws
// var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' });
const title = defaultTitle || 'excel-list'
// saveAs(new Blob([s2ab(wbout)], { type: "application/octet-stream" }), title + ".xlsx")
writeFileXLSX(wb, `${title}.xlsx`)
}
export function export_jsons_to_excel(
th1,
jsonData1,
th,
jsonData,
defaultTitle
) {
/* original data */
const data = jsonData
data.unshift(th)
data.unshift(jsonData1)
data.unshift(th1)
const ws_name = 'SheetJS'
const wb = new Workbook(),
ws = sheet_from_array_of_arrays(data)
/* 设置worksheet每列的最大宽度 */
const colWidth = data.map(row =>
row.map((val) => {
/* 先判断是否为null/undefined */
if (val == null) {
return { wch: 10 }
} else if (val.toString().charCodeAt(0) > 255) {
/* 再判断是否为中文 */
return { wch: val.toString().length * 2 }
} else {
return { wch: val.toString().length }
}
})
)
/* 以第一行为初始值 */
const result = colWidth[0]
for (let i = 1; i < colWidth.length; i++) {
for (let j = 0; j < colWidth[i].length; j++) {
if (result[j].wch < colWidth[i][j].wch) {
result[j].wch = colWidth[i][j].wch
}
}
}
ws['!cols'] = result
/* add worksheet to workbook */
wb.SheetNames.push(ws_name)
wb.Sheets[ws_name] = ws
// var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' });
const title = defaultTitle || 'excel-list'
// saveAs(new Blob([s2ab(wbout)], { type: "application/octet-stream" }), title + ".xlsx")
writeFileXLSX(wb, `${title}.xlsx`)
}
/**
* 表格导出
*
* @param {Array} columns 表格项列表 [{prop: 'name', label: '姓名'}, {prop: 'age', label: '年龄'}]
* @param {Array} list 表格数据列表
* @param {string} excelName 导出文件名
* @param {boolean} isNestedQuery 是否分析prop,嵌套查询数据
*/
export function export2Excel(columns, list, excelName, isNestedQuery = false) {
const labels = [] // 表头 ['姓名','年龄]
const props = [] // 属性 ['name','age']
columns.forEach((item) => {
labels.push(item.label)
props.push(item.prop)
})
// 获取导出数据: 遍历list,获取props
const data = list.map(row =>
props.map((prop) => {
if (!isNestedQuery || !prop.includes('.')) {
return row[prop]
} else {
// 嵌套查询
let a = row
const key = prop.split('.')
for (let i = 0; i < key.length; i++) {
a = a[key[i]]
}
return a
}
})
)
export_json_to_excel(labels, data, excelName)
}
vue
<script setup>
import { ref } from "vue";
import { export2Excel } from "@/utils/export2excel.js";
const tableData = ref([
{ no: 1, code: "A", name: "张三", gender: "男", intro: "我是张三" },
// ...
]);
const columns = [
{ label: "No.", prop: "no" },
{ label: "Code", prop: "code" },
{ label: "Name", prop: "name" },
{ label: "Gender", prop: "gender" },
{ label: "Intro", prop: "intro" }
];
function handleExport() {
export2Excel(columns, tableData.value, "test-file");
}
</script>
<template>
<h2>Export table to excel</h2>
<button @click="handleExport">Export</button>
<table><!-- ... --></table>
</template>
vue
<script setup>
import { ref } from "vue";
import { export_json_to_excel } from "@/utils/export2excel.js";
const data = ref([
[1,'A','张三','男','我是张三'],
// ...
]);
const header = ['No.', 'Code', 'Name', 'Gender', 'Intro'];
function handleExport() {
export_json_to_excel(header, data, "test-file");
}
</script>
<template>
<h2>Export table to excel</h2>
<button @click="handleExport">Export</button>
<table><!-- ... --></table>
</template>
封装方法中包含了多种场景下导出excel文件的功能
Last updated: