layui table.exportfile() 不支持合并单元格导出,因其底层仅读取扁平化列结构和 cache 数据,忽略 dom 中的 colspan/rowspan;需用 sheetjs 手动构建含 !merges 的工作表,严格按 excel 坐标系(0 起始、含首尾)设置合并区域,并匹配 mime 类型与文件后缀。
layui 的 table.exportfile() 原生不支持合并单元格导出——这不是配置问题,是底层逻辑缺失。你看到页面上渲染出的 colspan/rowspan 效果,导出时已被完全丢弃。
为什么 table.exportFile() 导出后合并全没了
它内部只读取 table.cache 和列定义(cols),把表头强行“拍平”成单行数组,然后拼 CSV 或伪装成 XLSX 的文本流。所有 colspan="3"、rowspan="2" 在导出路径里毫无意义,DOM 结构和 Excel 单元格之间没有映射关系。
- 错误现象:导出 Excel 打开后,原应合并的“成绩”标题变成两个空格+“语文”,数据列整体右移
- 传参加
mergeCells: true或修改headers无效——这些字段根本不在 layui 1.x/2.x 的 API 中 - 即使表格启用了
toolbar: true或自定义cols,导出仍只认 JS 初始化时的扁平列结构,无视 HTML 中写的colspan
用 SheetJS 手动构造带 !merges 的工作表
核心三步:取数据 → 构建二维表头数组 → 显式写 ws['!merges']。不要试图从 DOM 直接提取 colspan 值,必须按 Excel 的 0 起始索引重新推算坐标。
- 用
layui.table.cache['yourTableId']拿原始数据(注意:分页后只含当前页;如需全量,得调接口或改page: false) - 表头必须拆成多行二维数组,例如:
[['基本信息', null, '成绩'], ['姓名', '年龄', '语文', '数学', '英语']],其中null是占位符,表示该位置由上层合并覆盖 -
!merges里的每个对象描述一个矩形区域,s和e都是{r: 0, c: 0}形式,r和c从 0 开始计数,且包含首尾(即{r:0,c:1}到{r:0,c:3}表示跨 3 列) - 隐藏列(
hide: true)不参与数据列计数,但表头数组中对应位置必须留null或跳过,否则c索引偏移会导致整个合并错位
导出时 bookType 和 Blob 类型必须严格匹配
常见“文件损坏”或中文变方块,90% 出在这里:生成的是 xlsx 二进制流,却用错 MIME 类型包裹。
- 用
XLSX.write(wb, { type: 'array', bookType: 'xlsx' })得到Uint8Array -
Blob的type必须设为'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',不能简写为'xlsx'或'application/octet-stream' - 绝对不要用
text/csv;charset=utf-8包 xlsx 流——CSV 和 ZIP 结构不兼容,Excel 会拒绝解析 - 文件后缀名必须是
.xlsx,且与bookType: 'xlsx'一致;若写成.xls却用bookType: 'xlsx',Excel 直接报错
动态合并数据行(如相同 ID 合并)要自己算起止 r
这类合并不是靠表头,而是对 tbody 数据行操作,关键在偏移:表头占几行,数据行就从第几行开始算。
- 假设表头占 2 行,则第一行数据实际对应 Excel 的第 2 行(
r = 2),所以合并区间s.r要 +2 - 代码里别直接写
r: i,得写r: i + 2(2 是表头行数),否则合并会盖住表头或漏掉首行 - 连续值判断必须基于原始
table.cache数组顺序,不能依赖渲染后的 DOMtr顺序(排序、筛选后 DOM 顺序已变) -
!merges区域不能重叠、不能断开,Excel 解析器对这个数组极其敏感,差一位就整个合并失效
真正麻烦的从来不是写几行 !merges,而是把 DOM 里直观的 colspan="3" 翻译成 Excel 坐标系下的精确 {s:{r:0,c:1},e:{r:0,c:3}}——索引偏移、隐藏列占位、表头行数、数据起始行,任何一环算错,合并就消失。











