使用xlsx-js的json_to_sheet生成Excel时多余空单元格问题求助
解决xlsx-js中json_to_sheet生成Excel空行/空单元格问题
问题场景
在Vue3应用中使用xlsx-js库的json_to_sheet方法从JSON列表生成Excel时,若JSON对象是按字段拆分的同键条目(比如单独的name对象和age对象),会导致生成的表格出现多余空单元格,行被"占用"后后续字段会自动换行。
示例代码:
import * as XLSX from 'xlsx'; var wb = XLSX.utils.book_new(); var myws = XLSX.utils.json_to_sheet([ {"name": "Peter"}, {"name": "Adam"}, {"age": "13"}, {"age": "25"} ]); XLSX.utils.book_append_sheet(wb, myws, 'my_sheet1' );
当前生成的Excel输出:
|name |age | |Peter | | |Adam | | | | 13 | | | 25 |
期望输出:
|name |age | |Peter | 13 | |Adam | 25 |
补充场景:当输入为带分号分隔多值的人员对象(如爱好、好友),因Excel单单元格字符数限制拆分多值为同键的多个JSON对象时,同样会出现空行问题。
解决方案
1. 预处理JSON数据(最优方案)
核心思路是将分散的同索引字段合并为完整的对象,确保每个对象包含所有需要的列字段,这样json_to_sheet就能按行正常映射。
针对基础场景的处理代码:
import * as XLSX from 'xlsx'; // 原始拆分的JSON数组 const rawData = [ {"name": "Peter"}, {"name": "Adam"}, {"age": "13"}, {"age": "25"} ]; // 按字段分组,提取各字段的数组 const grouped = {}; rawData.forEach(item => { const key = Object.keys(item)[0]; if (!grouped[key]) grouped[key] = []; grouped[key].push(item[key]); }); // 合并为完整对象数组 const mergedData = []; const maxLength = Math.max(...Object.values(grouped).map(arr => arr.length)); for (let i = 0; i < maxLength; i++) { const obj = {}; Object.keys(grouped).forEach(key => { obj[key] = grouped[key][i] || ''; // 空值填充空字符串 }); mergedData.push(obj); } // 生成工作表 var wb = XLSX.utils.book_new(); var myws = XLSX.utils.json_to_sheet(mergedData); XLSX.utils.book_append_sheet(wb, myws, 'my_sheet1' );
针对补充场景(多值拆分)的处理:
拆分多值时,确保每个拆分后的对象保留所有字段,而非仅保留拆分的字段。比如原对象{"name":"Peter","hobbies":"reading;hiking","age":"25"},拆分爱好时生成:
// 正确的拆分方式 const processedData = [ {"name":"Peter","hobbies":"reading","age":"25"}, {"name":"Peter","hobbies":"hiking","age":"25"} ];
这样json_to_sheet生成的表格不会出现空行,同一行的其他字段会自动重复填充,符合Excel展示需求。
2. 生成工作表后手动清理空行
若无法预处理数据,可在生成工作表后遍历单元格,删除全空的行:
import * as XLSX from 'xlsx'; // 生成原始工作表 var wb = XLSX.utils.book_new(); var myws = XLSX.utils.json_to_sheet(rawData); XLSX.utils.book_append_sheet(wb, myws, 'my_sheet1' ); // 获取工作表范围 const range = XLSX.utils.decode_range(myws['!ref']); const rowsToKeep = []; // 遍历每一行,检查是否全空 for (let r = range.s.r; r <= range.e.r; r++) { let hasData = false; for (let c = range.s.c; c <= range.e.c; c++) { const cellAddress = XLSX.utils.encode_cell({r, c}); if (myws[cellAddress]) { hasData = true; break; } } if (hasData) rowsToKeep.push(r); } // 重新构建工作表数据 const newData = []; rowsToKeep.forEach(r => { const row = []; for (let c = range.s.c; c <= range.e.c; c++) { const cellAddress = XLSX.utils.encode_cell({r, c}); row.push(myws[cellAddress] ? myws[cellAddress].v : ''); } newData.push(row); }); // 生成新的工作表并替换原表 const newWs = XLSX.utils.aoa_to_sheet(newData); wb.Sheets['my_sheet1'] = newWs;
注意事项
json_to_sheet的默认行为是按对象出现的顺序依次填充行,若对象缺少之前出现过的键,会自动跳过已占用的行,这是导致空单元格的根本原因。- 预处理数据是最高效的解决方案,避免后续额外的工作表操作。
内容的提问来源于stack exchange,提问作者Dielna Reboot
相关产品推荐
相关产品推荐

