使用xlsx.js导出为excel,并实现自适应列宽
前言
- 使用的js库: xlsx.js
1 思路:
计算每一列所有单元格的文本长度(包括列头),取最大值作为列宽
2 代码:
getCellWidth为核心方法,用于计算单元格宽度的
如果包含中文,则宽度为:文本长度2.1,否则为:文本长度1.1,这个是我多次测试得到的数值
可以在此方法增加其他规则
function getCellWidth(value) {
// 判断是否为null或undefined
if (value == null) {
return 10
} else if (/.*[\u4e00-\u9fa5]+.*$/.test(value)) {
// 判断是否包含中文
return value.toString().length * 2.1
} else {
return value.toString().length * 1.1
/* 另一种方案
value = value.toString()
return value.replace(/[\u0391-\uFFE5]/g, 'aa').length
*/
}
}
// 经过评论反馈优化
function getCellWidth(value) {
// 判断是否为null或undefined
if (value == null) {
return 10;
} else if (/.*[\u4e00-\u9fa5]+.*$/.test(value)) {
// 中文的长度
const chineseLength = value.match(/[\u4e00-\u9fa5]/g).length;
// 其他不是中文的长度
const otherLength = value.length - chineseLength;
return chineseLength * 2.1 + otherLength * 1.1;
} else {
return value.toString().length * 1.1;
/* 另一种方案
value = value.toString()
return value.replace(/[\u0391-\uFFE5]/g, 'aa').length
*/
}
}
/**
* 将table、json数据导出为excel
* @param {object} options
* @param {[]} options.data 数据源
* @param {"table"|"json"|"aoe"} options.dataType 数据类型
* @param {string} options.sheetName sheet名称
* @param {boolean} options.saveFile 是否保存为文件,如果为false则返回workBook
* @param {string} options.fileName 文件名称
* @param {boolean} options.fitWidth是否自适应列宽(如果dataType="json",配置此属性将无效)
* @param {[]} options.header xlsx内部参数
*/
export function exportTo(
{
data = [],
dataType = 'table',
sheetName = 'Sheet1',
saveFile = true,
fileName = new Date().$toString() + '.xlsx',
fitWidth= true,
header = []
} = {}
) {
try {
if (!XLSX) throw 'exportTo: the plug-in "XLSX" is undefined.'
if (!data || data.length === 0) throw 'exportTo: data is null or undefined.'
let sheet = {}
switch (dataType) {
case 'table':
sheet = XLSX.utils.table_to_sheet(data, { raw: true })
break
case 'json':
sheet = XLSX.utils.json_to_sheet(data, { raw: true, header: header })
if (fitWidth) {
let colWidths = [],
colNames = Object.keys(data[0]) // 所有列的名称数组
// 计算每一列的所有单元格宽度
// 先遍历行
data.forEach((row) => {
// 列序号
let index = 0
// 遍历列
for (const key in row) {
if (colWidths[index] == null) colWidths[index] = []
switch (typeof row[key]) {
case 'string':
case 'number':
case 'boolean':
colWidths[index].push(getCellWidth(row[key]))
break
case 'object':
case 'function':
colWidths[index].push(0)
break
}
index++
}
})
sheet['!cols'] = []
// 每一列取最大值最为列宽
colWidths.forEach((widths, index) => {
// 计算列头的宽度
widths.push(getCellWidth(colNames[index]))
// 设置最大值为列宽
sheet['!cols'].push({ wch: Math.max(...widths) })
})
}
break
case 'aoe':
// 未实现
sheet = []
break
}
let workBook = {
SheetNames: [sheetName],
Sheets: {
[sheetName]: sheet
}
}
if (saveFile) {
XLSX.writeFile(workBook, fileName)
return true
} else {
return workBook
}
} catch (error) {
console.error('exportTo: ', error)
throw error
}
}
3 最终效果
后语
- getCellWidth方法可根据实际场景优化编写,尽量简洁,如果做过多判断和计算,数据量大了就会变得很慢
- exportTo方法在导出三列,4万行数据时的性能如下图,可参考
- 实现更复杂的导出功能,建议在后端服务实现,前端能力有限
- 其实wps都有这功能,鼠标点一下就行了,不过用户是上帝啊
weixin_45577889: 需要的,我也发现了这个问题
打碎了阳光: 外网可以唤醒吗,还是只支持局域网内的唤醒呢
weixin_46316529: vue文件可以格式化,但是ts文件不能格式化
陳平安啊: 没看懂,有成功过的吗?
moannian: 源码连接没有用了