非常符合前端直接的使用
使用
先看看使用
表格数据
const tableData = [
{
"id": 1,
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"age": 28,
"address": { "street": "123 Main St", "city": "Springfield", "state": "IL", "zip": "62701" }
},
{
"id": 2,
"firstName": "Jane",
"lastName": "Smith",
"email": "jane.smith@example.com",
"age": 34,
"address": { "street": "456 Elm St", "city": "Shelbyville", "state": "IL", "zip": "62565" }
},
{
"id": 3,
"firstName": "Bob",
"lastName": "Johnson",
"email": "bob.johnson@example.com",
"age": 23,
"address": { "street": "789 Oak St", "city": "Ogdenville", "state": "IL", "zip": "62075" }
}
]
使用方法
// 导出方法
exportExcel(
tableData, // 你的表格数据
[
{
title: 'ID', // 表头
wpx: 120, // 宽度
render: row => row.id, // 你要渲染的数据
},
{
title: '邮箱', // 表头
render: row => row.email, // 你要渲染的数据
},
{
title: '年龄',
wpx: 120,
render: row => (row.age < 18 ? '未成年' : '成年了'),
},
{
title: '地址',
wpx: 300,
render: row => row.address.street + '/' + row.address.city,
},
],
'用户数据.xlsx' // 导出的表名
)
封装
我们使用 xlsx
库的导出 Excel 功能
-
使用表格数据:
tableData
作为数据源,你通过一个配置对象数组定义了如何渲染每一列。每个配置对象包括表头、宽度和渲染函数等信息。 -
渲染函数: 通过
render
函数,你可以对每一行的数据进行自定义渲染,例如年龄列的情况,你区分了未成年和成年人。 -
列宽度: 通过
wpx
属性,你可以为每一列设置特定的宽度。 -
动态导入: 你使用了动态导入 (
import('xlsx').then(XLSX => {...})
) 来导入xlsx
库,这有助于代码分割和按需加载,提高了前端应用的性能。 -
文件名: 导出的文件名可以作为函数的参数传入,使其具有更好的灵活性。
安装xlsx
npm install xlsx -S
获取列名
通过 getColumnName来
function getColumnName(n) {
let columnName = "";
while (n > 0) {
const index = (n - 1) % 26;
columnName = String.fromCharCode(65 + index) + columnName;
n = Math.floor((n - 1) / 26);
}
return columnName;
}
getColumnName(1) // 返回 'A'
getColumnName(27) // 返回 'AA'
获取文本的宽度,用来给列的,要不然会出现列没有宽度的情况
const getWordCh = (val) => {
/* 先判断是否为null/undefined */
// eslint-disable-next-line eqeqeq
if (val == null) {
return 10;
} else if (val.toString().charCodeAt(0) > 255) {
/* 再判断是否为中文 */
return val.toString().length * 2;
} else {
return val.toString().length;
}
};
导出封装
import("xlsx")
动态引入 xlsx
const exportExcel = (dataSource, columns, filename) => {
import("xlsx").then((XLSX) => {
const sheet = {};
const defaultColumnCh = new Array(columns.length || 2);
const cols = [];
columns.forEach((item, index) => {
const letter = getColumnName(index + 1);
sheet[`${letter}1`] = { v: item.title };
defaultColumnCh[index] = 0;
});
dataSource.forEach((item, rowIndex) => {
columns.forEach((column, columIndex) => {
// @ts-ignore next-line
const value = column.render ? column.render(item) : item[column.field];
const letter = getColumnName(columIndex + 1);
sheet[letter + (rowIndex + 2)] = { v: value };
defaultColumnCh[columIndex] = Math.max(
defaultColumnCh[columIndex] || 0,
getWordCh(value)
);
});
});
columns.forEach((item, index) => {
// @ts-ignore next-line
const { render, title, field, ...ret } = item;
cols.push({
wch: Math.max(defaultColumnCh[index] || 0, getWordCh(title)),
...ret,
});
});
// 获取所有单元格的位置
const outputPos = Object.keys(sheet);
// 计算出范围 ,["A1",..., "H2"]
const ref = `${outputPos[0]}:${outputPos[outputPos.length - 1]}`;
sheet["!cols"] = cols;
sheet["!ref"] = ref;
console.log(" sheet: ", sheet);
// 导出 Excel
XLSX.writeFileXLSX(
{
SheetNames: ["Sheet1"],
Sheets: {
Sheet1: sheet,
},
},
filename
);
});
};
完整代码
/**
* 获取列名
@param {number}n 第几列,从1开始
@example
getColumnName(1) // 返回 'A'
getColumnName(27) // 返回 'AA'
*/
function getColumnName(n) {
let columnName = "";
while (n > 0) {
const index = (n - 1) % 26;
columnName = String.fromCharCode(65 + index) + columnName;
n = Math.floor((n - 1) / 26);
}
return columnName;
}
const getWordCh = (val) => {
/* 先判断是否为null/undefined */
// eslint-disable-next-line eqeqeq
if (val == null) {
return 10;
} else if (val.toString().charCodeAt(0) > 255) {
/* 再判断是否为中文 */
return val.toString().length * 2;
} else {
return val.toString().length;
}
};
/**
* 导出excel
* @example
exportExcel(
tableData, // 你的表格数据
[
{
title: 'ID', // 表头
wpx: 120, // 宽度
render: row => row.id, // 你要渲染的数据
},
{
title: '邮箱', // 表头
render: row => row.email, // 你要渲染的数据
},
{
title: '年龄',
wpx: 120,
render: row => (row.age < 18 ? '未成年' : '成年了'),
},
{
title: '地址',
wpx: 300,
render: row => row.address.street + '/' + row.address.city,
},
],
'用户数据.xlsx' // 导出的表名
)
*/
export const exportExcel = (dataSource, columns, filename) => {
import("xlsx").then((XLSX) => {
const sheet = {};
const defaultColumnCh = new Array(columns.length || 2);
const cols = [];
columns.forEach((item, index) => {
const letter = getColumnName(index + 1);
sheet[`${letter}1`] = { v: item.title };
defaultColumnCh[index] = 0;
});
dataSource.forEach((item, rowIndex) => {
columns.forEach((column, columIndex) => {
// @ts-ignore next-line
const value = column.render ? column.render(item) : item[column.field];
const letter = getColumnName(columIndex + 1);
sheet[letter + (rowIndex + 2)] = { v: value };
defaultColumnCh[columIndex] = Math.max(
defaultColumnCh[columIndex] || 0,
getWordCh(value)
);
});
});
columns.forEach((item, index) => {
// @ts-ignore next-line
const { render, title, field, ...ret } = item;
cols.push({
wch: Math.max(defaultColumnCh[index] || 0, getWordCh(title)),
...ret,
});
});
// 获取所有单元格的位置
const outputPos = Object.keys(sheet);
// 计算出范围 ,["A1",..., "H2"]
const ref = `${outputPos[0]}:${outputPos[outputPos.length - 1]}`;
sheet["!cols"] = cols;
sheet["!ref"] = ref;
console.log(" sheet: ", sheet);
// 导出 Excel
XLSX.writeFileXLSX(
{
SheetNames: ["Sheet1"],
Sheets: {
Sheet1: sheet,
},
},
filename
);
});
};