XLSX.js导出,支持单元格合并,背景色,列宽,字体大小等

这篇博客介绍了如何使用XLSX.js库结合xlsxStyle.js,实现前端Excel导出时支持单元格合并、背景色、列宽和字体大小等样式设置。作者提供了所需js文件的下载链接,并鼓励读者尝试并点赞。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

开始之前先上效果图,代码可直接复制前端使用,觉得不错的可以点个赞

1.需要用到的js自行下载

(1)js-xlsx.js
https://github.com/Ctrl-Ling/XLSX-Style-Utils或者https://github.com/SheetJS/js-xlsx
里面的xlsx.core.min.js或xlsx.full.min.js(本文用到xlsx.core.min.js)
(2)xlsxStyle.js
https://github.com/Ctrl-Ling/XLSX-Style-Utils
里面的xlsxStyle.core.min.js(本文用到xlsxStyle.core.min.js)
(3)xlsxStyle.utils.js
https://github.com/Ctrl-Ling/XLSX-Style-Utils
里面的xlsxStyle.utils.js

引入文件

<script src = '/xlsx.core.min.js' </script>;
<script src = '/xlsxStyle.core.min.js' </script>;
//表头
let tableHead = {
   'name': '姓名',
   'subject': '学科',
   'score': '成绩'
};
//json数据
let tableData=[{
   'name': '李明',
   'subject': '数学',//以下给该字段加上颜色,详情见代码
   'score': '98'
},{
   'name': '李明',
   'subject': '语文',
   'score': '96'
},{
   'name': '赵寻',
   'subject': {'value':'数学','fgColor':'92D050'},//这里为了演示自定义颜色数据格式
   'score': '95'
},{
   'name': '王力',
   'subject': '数学',
   'score': '80'
}];
let countNum = [];//统计相同姓名的占列个数
tableData.forEach(function (item) {
   if (countNum.hasOwnProperty(item.name)) {
      countNum[item.name]+=1;
   } else {
      countNum[item.name] = 1;
   }
});
let number = [];//将个数合并成新数组方便下面取值,(若有其他方法已拿到占列数可省略此步)
Object.keys(countNum).forEach((key) => {
   number.push(countNum[key])
});

let merges = [];//存统计好的,行和列的合并数组
let startRow = 1;//从第二行开始处理,跳过标题行
for (let i = 0; i < number.length; i++) {
   // 合并单元格处理's' 开始,'e' 结束,'c' 代表列,'r' 代表行,表格中行和列都是从下标0开始
   //所以:如:{s: {c: 0, r: 1}, e: {c: 0, r: 2}}表示execl中A2到A3合并
   for (let y = 0; y < 1; y++) {//这里默认只合并第一列(项目中可根据需求更改y的范围)
      let obj = {s: {c: y, r: startRow}, e: {c: y, r: startRow + number[i] - 1}};
      merges.push(obj);
   }
   startRow += number[i];//记录下一个实际要处理的行索引
}
tableData.unshift(tableHead);
let rowCount = tableData.length;//行数
let colCount = 3;//列数,这里传行数和列数是为了在下载方法中逐行设置背景色或字体
let colWidth = [14, 15, 15];//列宽默认从A往后排序
let filename = "file" + new Date().toISOString().replace(/[\-\:\.]/g, "");
exportxlsx_JsonMerges(tableData, filename, merges, rowCount, colCount, colWidth);

/**
 * @param data, json数组格式如['{'name':'阿张'},{'name':'小王'}']
 * @param fileName
 * @param int rowCount 行数
 * @param int colCount 列数
 * @param array colWidth 列宽默认从A开始 (数组长度等于列数)
 */
function exportxlsx_JsonMerges(data, fileName, merges, rowCount, colCount, colWidth) {
   if (isNaN(rowCount) || rowCount == 0 || isNaN(colCount) || colCount == 0) {
      alert(rowCount);
      alert(colCount);
      return;
   }
   let sheet = XLSX.utils.json_to_sheet(data, {skipHeader: true});//通过json_to_sheet转成单页(Sheet)数据,skipHeader为true不使用key为表头
   sheet['!merges'] = merges;
   sheet['!cols'] = [];
   if (colWidth.length != 0) {
      for (var item of colWidth) {
         // item指的的就是数组每一项的值
         sheet['!cols'].push({'wch': item})
      }
   }
   let bool = true;
   for (let i = 1; i <= rowCount; i++) {
      if (i != 1) {
         bool = false
      }
      for (let j = 1; j <= colCount; j++) {
         let lattice = getColName(j) + i;//单元格编号
         sheet[lattice].s = {
            border: {//添加边框颜色(表格中的线)
               bottom: {
                  style: 'thin',
                  color: '000000'
               },
               left: {
                  style: 'thin',
                  color: '000000'
               },
               right: {
                  style: 'thin',
                  color: '000000'
               },
               top: {
                  style: 'thin',
                  color: '000000'
               }
            },
            alignment: {
               horizontal: 'center', //水平居中
               vertical: 'center',//垂直居中
            },
            //字体类型、大小、是否加粗
            font: {//字体
               name: '宋体',
               sz: 12,
               bold: bool
            }
         };
         if (lattice === 'B2') { //这里固定给B2添加颜色
            sheet[lattice].s = {
               ...sheet[lattice].s,
               fill: { //背景色
                  fgColor: {rgb: '95B3D7'}
               },
               font: {//覆盖字体
                  name: '等线',
                  sz: 10,
                  bold: true
               },
            }
         }
         //这里自定义颜色,若是前端以对象传值时用到,这里数据格式为{'name':{'value':'李明','fgcolor':'ff0000'}}
         if (sheet[lattice].hasOwnProperty('value')) {
            sheet[lattice].v = sheet[lattice].value;
            delete sheet[lattice].value;
         }
         if (sheet[lattice].hasOwnProperty('fgColor')) {
            if (!sheet[lattice].hasOwnProperty('fill')) {
               sheet[lattice].s.fill = {};
            }
            sheet[lattice].s.fill.fgColor = {};
            sheet[lattice].s.fill.fgColor.rgb = sheet[lattice].fgColor;
            delete sheet[lattice].fgColor;
         }
      }
   }
   finalDownload(data, fileName, sheet, true)
}

/**
 * @param data
 * @param fileName
 * @param sheet
 * @param style 是否带样式导出
 */
function finalDownload(data, fileName, sheet, style = false) {
   const wb = {SheetNames: ['Sheet1'], Sheets: {}, Props: {}};
   wb.Sheets['Sheet1'] = sheet;
   const wopts = {
      bookType: 'xlsx', // 要生成的文件类型
      bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
      type: 'binary'
   };
   if (style == true) {
      //用XlsxStyle类,可设置样式
      saveAs(new Blob([s2ab(xlsxStyle.write(wb, wopts))], {type: "application/octet-stream"}), fileName + '.xlsx');
   } else {
      //无样式下载
      saveAs(new Blob([s2ab(XLSX.write(wb, wopts))], {type: "application/octet-stream"}), fileName + '.xlsx');
   }
}

/**
 * @param s
 * @returns {ArrayBuffer}
 */
function s2ab(s) {
   var buf = new ArrayBuffer(s.length);// 字符串转ArrayBuffer
   var view = new Uint8Array(buf);
   for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
   return buf;
}

/**
 * @param obj
 * @param fileName
 */
function saveAs(obj, fileName) {//自定义下载文件方式
   var tmpa = document.createElement("a");
   tmpa.download = fileName || "下载";
   tmpa.href = URL.createObjectURL(obj); //绑定a标签
   tmpa.click(); //模拟点击实现下载
   setTimeout(function () { //延时释放
      URL.revokeObjectURL(obj); //用URL.revokeObjectURL()来释放这个object URL
   }, 100);
}

/**
 * 根据数字获取列名
 * @colCount 列序号
 * @returns 列名
 */
function getColName(colCount) {
   if (colCount < 0) {
      return '';
   }
   let wantedColName = '';
   while (colCount > 0) {
      end = colCount % 26;
      wantedColName = String.fromCharCode(65 + end - 1) + wantedColName;//65开始表示A列
      colCount = Math.floor(colCount / 26);
   }
   return wantedColName;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值