0、有引用库,table2excel,参考demo文件
1、调用示例
const config = {
name: '导出文件',
data: [
{ name: '测试1', time: '2023年', status: '001', age: '11' },
{ name: '测试2', time: '2023年', status: '001', age: '11' },
{ name: '测试3', time: '2023年', status: '001', age: '12' },
{ name: '测试4', time: '2023年', status: '001', age: '13' },
{ name: '测试5', time: '2023年', status: '001', age: '14' },
],
columnsData: [
{
label: '学生信息',
children: [
{
label: "姓名",
prop: 'name',
},
{
label: "时间",
prop: 'time',
},
{
label: "年龄",
prop: 'age',
},
]
},
]
}
exportExcelUitl.export(config)
2、核心代码
const exportExcelUitl = {}
!function(){
// vNode对象转为html字符串
const vnodeToString = function (vnode) {
// 如果是文本节点,直接返回文本内容
if (['string', 'boolean', 'undefined', 'null', 'number'].includes(typeof vnode) || !vnode) {
return vnode;
}
// 转换节点的属性为字符串形式
const attrs = Object.keys(vnode.attrs || {})
.map((key) => `${key}="${vnode.attrs[key]}"`)
.join(' ');
// 转换子节点为字符串形式
const children = (vnode.children || [])
.map(vnodeToString)
.join('');
// 返回包含标签名、属性和子节点的字符串形式
return `<${vnode.tag} ${attrs}>${children}</${vnode.tag}>`;
}
this.vnodeToString = vnodeToString
class DataToExcelHtml {
// 标题
title = ''
// 原始数据
originalData = []
// 表格列配置数据
columnsData = []
// 渲染数据vNode
renderData = []
// 表头vNode数据
headerVNode = []
// 表体vNode数据
bodyVNode = []
// table标签的dom的id
tableDomId = 'excel-line-data'
// 列宽
colWidth = 120
constructor(config) {
this.tableDomId = config.tableDomId
this.dom = config.dom
this.colWidth = config.colWidth || 120
this.originalData = config.data
this.columnsData = config.columnsData
this._setColIndex()
this.headerVNode = this._setHeaderVNode()
this.bodyVNode = this._setBodyVNode()
this.setInnerHtml()
}
// 取最后一层
flattenObjectArrayLast(arr, key = "children") {
let flattened = [];
arr.forEach(v => {
if (v.children && v.children.length > 0) {
flattened = flattened.concat(this.flattenObjectArrayLast(v[key]))
} else {
flattened.push(v);
}
})
return flattened;
}
// 表头 设置每个字段所在的列 行下标值
_setColIndex(data = this.columnsData, index = 0, row_index = 0) {
data.forEach(v => {
v.__colspan = this.flattenObjectArrayLast(v.children || []).length || 1
v.__rowspan = v.rowspan || 1
v.__col_index = v.__colspan > 1 ? null : index
v.__row_index = row_index
index++
if (v.children?.length) {
index = this._setColIndex(v.children, index, row_index + 1)
}
})
return index
}
// 设置样式
_setStyle(col) {
// 表样式通用
const commonTrStyle = "height: 30px;"
const commonBorder = 'border-width:1px;border-style:solid;border-color:#000000;'
const commonAttrsLabel = {
style: `text-align:${col.align || 'center'};font-size: 12px;` + commonBorder + commonTrStyle + col.styleStr,
}
return commonAttrsLabel
}
// 设置表头
_setHeaderVNode(data = this.columnsData) {
const that = this
// 递归获取表头合并行深度
let deep = (function getDeep(list) {
let deep = 1
list.forEach(col => {
let curDeep = 1
if (col.children && col.children.length) {
curDeep += getDeep(col.children)
}
deep = curDeep > deep ? curDeep : deep
})
return deep
})(data)
// 递归获取表头VNode
this.headerVNode = (function recData(list, curDeep = 1, tr = []) {
list.forEach(col => {
tr[col.__row_index] = tr[col.__row_index] || { tag: 'tr', children: [] }
const obj = {
tag: 'td',
children: [col.label],
attrs: {
style: that._setStyle(col).style,
rowspan: col.__rowspan || 1,
colspan: col.__colspan || 1,
width: col.width || that.colWidth,
}
}
if (col.children) {
recData(col.children, curDeep++, tr)
} else if (!col.children?.length) {
}
tr[col.__row_index].children.push(obj)
})
return tr
})(data)
return this.headerVNode
}
_setBodyVNode(data = this.originalData, columnsData = this.columnsData) {
const flatColumns = this.flattenObjectArrayLast(columnsData).filter(v => v.__col_index !== null)
function getChild(row, col, index) {
if (col.type === 'index') {
return index + 1
}
return row[col.prop] || ''
}
this.bodyVNode = data.map((row, index) => {
const tr = { tag: 'tr', children: [] }
// 列下标
flatColumns.forEach((col, idx) => {
tr.children.push({
tag: 'td',
children: [getChild(row, col, index)],
attrs: {
style: this._setStyle(col).style,
}
})
})
return tr
})
return this.bodyVNode
}
// 设为innerHtml
setInnerHtml(vNode = this.headerVNode) {
const i = vnodeToString({
tag: 'table',
attrs: {
style: "border-collapse: collapse;border:1px",
border: 1,
cellspacing: '0',
id: this.tableDomId
},
children: [{
tag: 'tbody',
attrs: {
style: ""
},
children: [].concat(vNode, this.bodyVNode)
}]
})
this.dom.innerHTML = i
}
}
this.DataToExcelHtml = DataToExcelHtml
this.export = function (config) {
const dom = document.createElement('div');
dom.style.position = 'fixed'
dom.style.opacity = 0
document.body.appendChild(dom);
config.dom = dom
config.tableDomId = 'table__onlyId_' + new Date().getTime()
new DataToExcelHtml(config)
new Table2Excel('#' + config.tableDomId).export(config.name || ('导出表格' + new Date().getTime()))
setTimeout(() => {
dom.parentNode.removeChild(dom);
}, 1000)
}
}.call(exportExcelUitl)