vue中使用xlsx导出Excel 并设置样式,解决未完全合并单元格框线的BUG

本文介绍了在前端开发中使用npm包xlsx进行表格导出时遇到的问题,如版本不匹配、xlsx-style报错,以及如何通过修改模块路径和设置样式来解决。作者详细展示了如何加载表格、设置列宽和单元格样式,以确保导出的Excel文件符合预期。

今天有需到一个需求,需要在前端直接导出表格,将了解发现了npm上用的比较多的 xlsx 这个包,但是在使用过程中发现很多问题,下边是我将发现问题进行的汇总以及相应的解决办法。

1.安装

首先说安装问题,防止版本不对应导致运行报错,或者XLSX导入之后会出现undefined等问题,建议package.json锁以下版本:

"xlsx": "0.16.0", 
// 这个包是用来导出(其实不安装这个包,使用创建虚拟a标签然后click的方式也可)
"file-saver": "2.0.2",
// 这个包是用来设置样式
"xlsx-style": "^0.8.13",
2.报错解决

在使用 xlsx-style 时,可能会出现以下报错

This relative module was not found:

* ./cptable in ./node_modules/xlsx-style/dist/cpexcel.js

解决办法: 找到 ./node_modules/xlsx-style/dist/cpexcel.js 文件手动修改

815var cpt = require('./cpt' + 'able'); 
替换为
var cpt = cptable;
3.使用
import FileSaver from 'file-saver';
import XLSX from 'xlsx';
import XLSXS from 'xlsx-style';

// 点击事件触发的方法
download() {
	  // 首先加载  <table id='excelTable'> 标签 为 workbook对象
      let workbook = XLSX.utils.table_to_book(document.getElementById('excelTable'));
      // 先定义列宽 , 我这里文件一共有7 列 ,所以设置7列宽度相等都为 20 ,如果你有很多列建议直接 map() 
      let wscols = [
        { wch: 20 },
        { wch: 20 },
        { wch: 20 },
        { wch: 20 },
        { wch: 20 },
        { wch: 20 },
        { wch: 20 }
      ];
      // 获取 需要设置样式的 sheet ,我这里只有 一个 sheet 所以索引默认加载了第一个
      const sheet = workbook.Sheets[workbook.SheetNames[0]];
      // 设置列宽 
      sheet['!cols'] = wscols;
      
      // 定义框线样式
      const borderAll = {
        color: { auto: 1 },
        top: {style: "thin"},
        bottom: { style: "thin"},
        left: { style: "thin" },
        right: { style: "thin" }
      };
	
	// 这里的意思为 先默认代表表格的 7 个列  的 列号 
	// 比如 A2 意思是 第一列 第2行
      const _letterList = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
	// 定义一个 箭头函数,接受三个参数,分别为 当前Sheet , 行列号(例如:‘A2’), 是否是新增样式
      const _mapCellStyle = (_sheet, _key, _type) => {
        const _cellStyle = {
          border: borderAll,
          alignment: {
            wrapText: true,
            horizontal: "center",
            vertical: "center"
          },
          font: {
            name: "微软雅黑",
            sz: 10
          },
          bold: true,
          numFmt: "0"
        }

        if (_type === 'append') {
        // 需要新增样式,说明当前加载的sheet中并不存在该单元格,可能当前单元格被前边合并,这种被合并的单元格也得设置样式,
        // 否则就会出现 合并单元格只有第一格带框线,后边没框线的情况出现,所以这里需要将后边的边框样式也加上。
          _sheet[_key] = {
            s: _cellStyle
          }
        } else {
        // 若不是新增样式 则代表sheet中已存在该表格直接修改其 s 属性即可使属性生效
          if (typeof _sheet[_key] === 'object') {
            _sheet[_key].s = _cellStyle
          }
        }
      }
		
	// sheet 不懂得可以单独打印一下,它其实就是一个对象,键代表行列号(‘A2’),值为该单元格的值,样式等,
	// 我们需要做的就是修改其值中的样式
      Object.keys(sheet).forEach((i, _) => {
      // 无用属性直接过滤
        if (i !== "!ref" || i !== "!cols" || i !== "!merges" || i !== "Am") {
          // 首先设置遍历到的 当前 key 
          let _nowKey = i
          // 然后调用 _mapCellStyle  渲染当前单元格样式
          _mapCellStyle(sheet, _nowKey)
		 // 我们这里先获取下一个行列号  例如当前_nowKey 是 A1  这里就是获取到 B1 ,及 当前行的 下一列数据
          let _nextKey = _letterList[_letterList.indexOf(_nowKey[0]) + 1] + i.slice(1)
          
		// 判断 B1 是否在 Sheet的key中,如果不存在,只可能是因为B1所在单元格已经被A1所合并,所以我们需要将B1也调用一下  _mapCellStyle 
		// 渲染 B1 的样式,不然就会出现 A1 B1 这两格是合并的状态,只有A1有框线,而B1 没有框线的情况。
		// 这里用 while 就是 要把需要合并的单元格全部 渲染上样式,直到可能 B4 在 Sheet中 停止
          while (_nowKey[0] !== 'G' && !Object.keys(sheet).includes(_nextKey)) {
            _mapCellStyle(sheet, _nextKey, 'append')
            // 这里就是简单的交换索引
            _nowKey = _nextKey
            _nextKey = _letterList[_letterList.indexOf(_nowKey[0]) + 1] + _nowKey.slice(1)
          }
        }
      })

      let wopts = {
        bookType: 'xlsx',
        bookSST: false,
        type: 'buffer',
      }
      let _blob = XLSXS.write(workbook, wopts);

      FileSaver.saveAs(new Blob([_blob], {
        type: "application/octet-stream"
      }), "项目信息一张表.xlsx");
    },
Vue 前端使用 `xlsx` 和 `xlsx-style` 库可以实现导出 Excel 文件设置字体、列宽、行高、对齐方式以及合并单元式化效果。以下是具体实现步骤和示例代码。 ### 安装依赖 首先需要安装 `xlsx-js-style`,它支持样式设置,包括字体、背景色、边等: ```bash npm install --save xlsx-js-style ``` ### 导出 Excel 设置样式 #### 设置字体样式、对齐方式和背景色 通过为单元对象添加 `s` 属性来定义样式,可以设置字体加粗、居中对齐以及填充颜色: ```vue <script setup> import XLSX from "xlsx-js-style"; const download = () => { const wb = XLSX.utils.book_new(); const ws = XLSX.utils.aoa_to_sheet([ ["Hello", "World"], [1, 2], ]); // 设置 A1 单元样式:加粗、居中、红色背景 ws["A1"].s = { font: { bold: true, }, alignment: { horizontal: "center", }, fill: { fgColor: { rgb: "FFFF0000" } }, }; // 设置 B2 单元样式:加粗、居中、红色背景 ws["B2"].s = { alignment: { horizontal: "center" }, font: { bold: true }, fill: { fgColor: { rgb: "FFFF0000" } }, }; XLSX.utils.book_append_sheet(wb, ws, "Sheet1"); XLSX.writeFile(wb, "example.xlsx"); }; </script> ``` 上述代码展示了如何为特定单元应用字体加粗、水平居中对齐以及红色背景填充[^1]。 #### 设置列宽 可以通过修改 `ws['!cols']` 数组来控制每列的宽度,单位为像素(`wpx`)或字符数(`wch`): ```javascript // 设置第一列为120像素宽,其余列为60像素宽 const sum = 5; // 总列数 for (let i = 0; i < sum; i++) { if (i === sum - 1) { ws["!cols"][i] = { wpx: 120 }; } else { ws["!cols"][i] = { wpx: 60 }; } } ``` 该方法可用于根据实际内容调整不同列的宽度,以确保表显示美观[^2]。 #### 设置行高 虽然 `xlsx-js-style` 不直接提供设置行高的 API,但可以通过操作底层结构来实现。通常建议在 Excel 打开后手动调整行高,或者结合其他库进行更复杂的操作。 #### 合并单元 使用 `sheet["!merges"]` 数组定义合区域,每个合项是一个包含起始和结束行列索引的对象: ```javascript // 合从 A1 到 D1 的区域 ws["!merges"] = [ { s: { r: 0, c: 0 }, e: { r: 0, c: 3 } } ]; ``` 此方法允许将多个单元成一个大单元,适用于表头或跨列展示的内容[^1]。 ### 完整示例 综合以上功能,以下是一个完整的 Vue 组件示例,用于导出带有多种式的 Excel 文件: ```vue <template> <button @click="download">导出 Excel</button> </template> <script setup> import XLSX from "xlsx-js-style"; const download = () => { const wb = XLSX.utils.book_new(); const ws = XLSX.utils.aoa_to_sheet([ ["标题", "", "", ""], ["Hello", "World", "数据1", "数据2"], [1, 2, 3, 4], ]); // 设置 A1 样式 ws["A1"].s = { font: { bold: true }, alignment: { horizontal: "center" }, fill: { fgColor: { rgb: "FFFF0000" } }, }; // 合 A1 到 D1 ws["!merges"] = [{ s: { r: 0, c: 0 }, e: { r: 0, c: 3 } }]; // 设置列宽 for (let i = 0; i < 4; i++) { ws["!cols"][i] = { wpx: 100 }; } XLSX.utils.book_append_sheet(wb, ws, "Sheet1"); XLSX.writeFile(wb, "formatted_example.xlsx"); }; </script> ``` ###
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值