vue3+vite项目 使用xlsx-style-vite 导出自定义单元格/边框颜色/背景色

目录

准备工作:

1.安装依赖

2.解决:导出excel合并单元格后边框缺失问题

3.单元格样式/边框颜色/背景色/文字 等样式 设置

4.先看一下 我这里是封装导出方法来做的,不需要封装的可直接放到页面中去

这里有三种形式:

1.使用tableId 直接导出页面所显示表格

表格ui图

完整代码

导出结果

2.使用tableId 导出 带有合计行 的表格(带有合计行并且有多级表头 底部合计行会显示错乱)

详解:参数分解

完整代码

表格ui图:原图表格数据较长 这里显示了3分之1

导出结果:

3.自定义表头/表格内容 处理成二维数组格式 导出

参数详解

完整代码

表格ui图:

导出结果:


准备工作:

1.安装依赖/引入页面
npm install xlsx xlsx-style-vite file-saver --save
# 或
yarn add xlsx xlsx-style-vite file-saver
import * as XLSX from "xlsx"; //默认导出无法修改样式
import FileSaver from "file-saver";
// @ts-ignore
import * as XLSX_STYLE from "xlsx-style-vite"; // 需要自定义样式 必须安装
2.解决:导出excel合并单元格后边框缺失问题
//第一种 直接根据表格id  $table 导出excel
let ws = XLSX.utils.table_to_sheet(document.querySelector($table));  //表格id $table
//第二种 自己转化自定义数据 转化为二维数组 data 再导出excel
let ws = XLSX.utils.aoa_to_sheet(data) //data 二维数组

const mergeCell = (ws) => {
    const borderStyle = {
        top: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
        bottom: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
        left: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
        right: {style: 'thin', color: {rgb: 'CCCCCCCC'}}
    };
// 遍历所有单元格,确保合并区域每个单元格都有边框
    const range = XLSX.utils.decode_range(ws['!ref']);
    for (let R = range.s.r; R <= range.e.r; R++) {
        for (let C = range.s.c; C <= range.e.c; C++) {
            const cellAddr = XLSX.utils.encode_cell({r: R, c: C});
            if (!ws[cellAddr]) ws[cellAddr] = {};
            ws[cellAddr].s = {...ws[cellAddr].s, border: borderStyle};  // 显式设置边框‌:ml-citation{ref="4,8" data="citationList"}
        }
    }
    return ws
};
3.单元格样式/边框颜色/背景色/文字 等样式 设置
s: {
  border: {
    top: {style: 'thin', color: {rgb: '000000'}},
    bottom: {style: 'thin', color: {rgb: '000000'}},
    left: {style: 'thin', color: {rgb: '000000'}},
    right: {style: 'thin', color: {rgb: '000000'}},
  },
  alignment: {
    horizontal: 'center',//水平居中对齐
      vertical: 'center',//垂直居中
      wrapText: true,//自动换行
  },
  fill: {
    fgColor: { rgb: 'cccccc' },
  },
}
4.先看一下 我这里是封装导出方法来做的,不需要封装的可直接放到页面中去

这里有三种形式:

1.使用tableId 直接导出页面所显示表格
表格ui图

完整代码

导出按钮 以及参数详解

<script lang="ts" name="trafficStatistics" setup>
//导出exc
const exportAllBtn = () => {
  //参数1:表格数据 id或者 class
  //参数2:导出文件名 自定义
  //参数3:是否是多级表头
  //参数4:是否是需要添加表格样式
  complexTableStyle('#dailyTrafficTable','流量统计表.xlsx',true,true)
};
</script>

 封装的公共导出代码

import {h} from "vue";
import * as XLSX from "xlsx";
import FileSaver from "file-saver";
// @ts-ignore
import * as XLSX_STYLE from "xlsx-style-vite";
/**
 ************************************** 导出 start ************************************************
 */
//表格样式
const setPubExcel = (data) => {
    data["!cols"] = [];
    const excludes = ['!cols', '!fullref', '!merges', '!ref', '!rows'];
    for (let key in data) {
       //data["!cols"].push({ wpx: 180 }); //给单元格添加宽度 可以自己判断文字有多少给出对应的宽度
        if (data.hasOwnProperty(key)) {
            if (!excludes.includes(key)) {
                console.log(data)
                data[key].s = {
                    border: {
                        top: {style: 'thin', color: {rgb: '000000'}},
                        bottom: {style: 'thin', color: {rgb: '000000'}},
                        left: {style: 'thin', color: {rgb: '000000'}},
                        right: {style: 'thin', color: {rgb: '000000'}},
                    },
                    alignment: {
                        horizontal: 'center',//水平居中对齐
                        vertical: 'center',//垂直居中
                        wrapText: true,//是否换行
                    },
                    fill: {
                        fgColor: { rgb: 'cccccc' },
                    },
                }
            }
        }
    }
};
// 合并行列样式
const mergeCell = (ws) => {
    const borderStyle = {
        top: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
        bottom: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
        left: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
        right: {style: 'thin', color: {rgb: 'CCCCCCCC'}}
    };
// 遍历所有单元格,确保合并区域每个单元格都有边框
    const range = XLSX.utils.decode_range(ws['!ref']);
    for (let R = range.s.r; R <= range.e.r; R++) {
        for (let C = range.s.c; C <= range.e.c; C++) {
            const cellAddr = XLSX.utils.encode_cell({r: R, c: C});
            if (!ws[cellAddr]) ws[cellAddr] = {};
            ws[cellAddr].s = {...ws[cellAddr].s, border: borderStyle};  // 显式设置边框‌:ml-citation{ref="4,8" data="citationList"}
        }
    }
    return ws
};
//字符串转ArrayBuffer
const s2ab = (s) => {
    const buf = new ArrayBuffer(s.length);
    const view = new Uint8Array(buf);
    for (let i = 0; i < s.length; i++) {
        view[i] = s.charCodeAt(i) & 0xff;
    }
    return buf;
};

/**
 *导出 一般/复杂 表格  按照显示的表格所导出,不需要自定义表头
 *可参考 复杂表格:统计-日流量统计 一般表格:统计- 机场架次航班流量统计表
 * 参数1:表格数据 id或者 class
 * 参数2:导出文件名 自定义
 * 参数3:是否是需要添加表格样式          默认:添加表格样式
 * 参数4:是否是需要添加合并单元格表格样式  默认:添加合并单元格表格样式
 * 参数5:是否有合计行                  默认 false
 * 参数6:表头合并了几行+一页多少条       默认:0 当有合计行时 须传
 */
// 直接导出一般/多级表头 表格数据
export function complexTableStyle($table, name, setPub = true, merge = true) {
    let workbook = XLSX.utils.book_new();
    let wb = XLSX.utils.table_to_sheet(document.querySelector($table));
    //下面直接放wb数据 可直接使用 自测
    XLSX.utils.book_append_sheet(workbook, wb, 'Sheet1');
    if (setPub) setPubExcel(wb); //默认带 表格样式
    if (merge) mergeCell(wb) //默认带 合并单元格表格样式
    let wBout = XLSX_STYLE.write(workbook, {bookType: 'xlsx', bookSST: false, type: 'binary',});
    FileSaver.saveAs(new Blob([s2ab(wBout)], {type: 'application/octet-stream;charset=utf-8"'}), `${name}`)
}
/**
 ************************************** 导出 end ************************************************
 */
导出结果

整体表格加了 背景色 边框 (可遍历数组给指定单元格加样式)

2.使用tableId 导出 带有合计行 的表格(带有合计行并且有多级表头 底部合计行会显示错乱)
详解:参数分解

完整代码

可以不使用组件 组件中的方法直接放到页面中就可以

导出按钮执行方法

<script lang="ts" name="airportSupportFlight" setup> 
  import {complexTableSum} from '/@/utils/common'; //引入组件
  //导出excel
  const exportAllBtn = () => {
    // 参数1:表格数据 id或者 class
    // 参数2:导出文件名 自定义
    // 参数3:是否是需要添加表格样式          默认:添加表格样式
    // 参数4:是否是需要添加合并单元格表格样式  默认:添加合并单元格表格样式
    // 参数5:是否有合计行                  默认 false
    // 参数6:表头合并了几行+一页多少条       默认:0 当有合计行时 须传
    complexTableSum('#airportSupportFlight','机场保障航班架次-自定义.xlsx',true,true,true,paginationData.pageSize + 3)
  };
</script>

封装组件公共代码

import {h} from "vue";
import * as XLSX from "xlsx";
import FileSaver from "file-saver";
// @ts-ignore
import * as XLSX_STYLE from "xlsx-style-vite";

/**
 ************************************** 导出 start ************************************************
 */
//表格样式
const setPubExcel = (data) => {
    console.log(8, data)
    data["!cols"] = [];
    const excludes = ['!cols', '!fullref', '!merges', '!ref', '!rows'];
    for (let key in data) {
             //data["!cols"].push({ wpx: 180 }); //给单元格添加宽度 可以自己判断文字有多少给出对应的宽度
        if (data.hasOwnProperty(key)) {
            if (!excludes.includes(key)) {
                data[key].s = {
                    border: {
                        top: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
                        bottom: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
                        left: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
                        right: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
                    },
                    alignment: {
                        horizontal: 'center',//水平居中对齐
                        vertical: 'center',//垂直居中
                        wrapText: true,//是否换行
                    },
                    fill: {
                        // fgColor: { rgb: '0070C0' },//背景色
                    },
                }
            }
        }
    }
};
// 合并行列样式
const mergeCell = (ws) => {
    const borderStyle = {
        top: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
        bottom: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
        left: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
        right: {style: 'thin', color: {rgb: 'CCCCCCCC'}}
    };
// 遍历所有单元格,确保合并区域每个单元格都有边框
    const range = XLSX.utils.decode_range(ws['!ref']);
    for (let R = range.s.r; R <= range.e.r; R++) {
        for (let C = range.s.c; C <= range.e.c; C++) {
            const cellAddr = XLSX.utils.encode_cell({r: R, c: C});
            if (!ws[cellAddr]) ws[cellAddr] = {};
            ws[cellAddr].s = {...ws[cellAddr].s, border: borderStyle};  // 显式设置边框‌:ml-citation{ref="4,8" data="citationList"}
        }
    }
    return ws
};
//字符串转ArrayBuffer
const s2ab = (s) => {
    const buf = new ArrayBuffer(s.length);
    const view = new Uint8Array(buf);
    for (let i = 0; i < s.length; i++) {
        view[i] = s.charCodeAt(i) & 0xff;
    }
    return buf;
};

/**
 *导出 一般/复杂 表格  按照显示的表格所导出,不需要自定义表头
 *可参考 复杂表格:统计-日流量统计 一般表格:统计- 机场架次航班流量统计表
 * 参数1:表格数据 id或者 class
 * 参数2:导出文件名 自定义
 * 参数3:是否是需要添加表格样式          默认:添加表格样式
 * 参数4:是否是需要添加合并单元格表格样式  默认:添加合并单元格表格样式
 * 参数5:是否有合计行                  默认 false
 * 参数6:表头合并了几行+一页多少条       默认:0 当有合计行时 须传
 */
// 直接导出表格数据 + 合计行
export function complexTableSum($table, name, setPub = true, merge = true, getSummaries = false, numRow = 0) {
    let workbook = XLSX.utils.book_new();
    let wb = XLSX.utils.table_to_sheet(document.querySelector($table));
    XLSX.utils.book_append_sheet(workbook, wb, 'Sheet1');
    if (getSummaries) { //有合计行
        let mergesAll = wb['!merges']
        let merges = []
        for (let i in mergesAll) {
            if (mergesAll[i].s.r < numRow) {
                merges.push(mergesAll[i])
            }
        }
        wb['!merges'] = merges
    }
    if (setPub) setPubExcel(wb); //默认带 表格样式
    if (merge) mergeCell(wb) //默认带 合并单元格表格样式
    let wBout = XLSX_STYLE.write(workbook, {bookType: 'xlsx', bookSST: false, type: 'binary',});
    FileSaver.saveAs(new Blob([s2ab(wBout)], {type: 'application/octet-stream;charset=utf-8"'}), `${name}`)
}
/**
 ************************************** 导出 end ************************************************
 */
表格ui图:原图表格数据较长 这里显示了3分之1

导出结果:

3.自定义表头/表格内容 处理成二维数组格式 导出
参数详解

完整代码

导出执行方法 这里写死了二维数组 做测试用


//导出exc 这里只做测试 写死数据
const exportAllBtn = () => {
  //自定义的表头  需要自行转换格式  
  let allHeader = [
    [
      "离港正常率排名",
      "",
      "",
      "",
      "",
      "",
      "",
      "",
      "",
      "",
      "",
      "",
      "",
      "",
      "原因"
    ],
    [
      "离港机场",
      "排名",
      "所属航空公司",
      "航班号",
      "起落机场及时刻",
      "计划航班数",
      "正常航班数",
      "航班正常率",
      "公司",
      "天气",
      "空管",
      "军事",
      "时刻",
      "其他",
      ""
    ]
  ]
  //多级表头 合集prop
  let filterVal = [
    "flno",
    "flno",
    "flno",
    "flno",
    "flno",
    "qchb",
    "flystart",
    "flyend",
    "delayreason",
    "delay1",
    "godelay",
    "godelay",
    "godelay",
    "godelay",
    "reason"
] 
  //表格数据
  let dataList = [
  {flno:'11',"qchb":'222',"delay1":'333',"godelay":'444','reason':''},
  {flno:'11',"qchb":'222',"delay1":'333',"godelay":'444','reason':''}
]
  //合并单元格数据
  let merges = ['A1:N1', 'O1:O2'] 
  complexTableCustomStyle(allHeader, dataList, filterVal, '四大机场国内离港正常率排名后三位航班统计表.xlsx', merges)
};

封装组件公共代码

import * as XLSX from "xlsx";
import FileSaver from "file-saver";
// @ts-ignore
import * as XLSX_STYLE from "xlsx-style-vite";

/**
 ************************************** 导出 start ************************************************
 */
//处理数据格式为二维数组
const formatJson = function (filterVal, list) {
    return list.map((v, i) => filterVal.map(j => {
        return v[j]
    }))
}
//表格样式
const setPubExcel = (data) => {
    data["!cols"] = [];
    const excludes = ['!cols', '!fullref', '!merges', '!ref', '!rows'];
    for (let key in data) {
             //data["!cols"].push({ wpx: 180 }); //给单元格添加宽度 可以自己判断文字有多少给出对应的宽度

        if (data.hasOwnProperty(key)) {
            if (!excludes.includes(key)) {
                data[key].s = {
                    border: {
                        top: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
                        bottom: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
                        left: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
                        right: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
                    },
                    alignment: {
                        horizontal: 'center',//水平居中对齐
                        vertical: 'center',//垂直居中
                        wrapText: true,//是否换行
                    },
                    fill: {
                        // fgColor: { rgb: '0070C0' },
                    },
                }
            }
        }
    }
};
// 合并行列样式
const mergeCell = (ws) => {
    const borderStyle = {
        top: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
        bottom: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
        left: {style: 'thin', color: {rgb: 'CCCCCCCC'}},
        right: {style: 'thin', color: {rgb: 'CCCCCCCC'}}
    };
// 遍历所有单元格,确保合并区域每个单元格都有边框
    const range = XLSX.utils.decode_range(ws['!ref']);
    for (let R = range.s.r; R <= range.e.r; R++) {
        for (let C = range.s.c; C <= range.e.c; C++) {
            const cellAddr = XLSX.utils.encode_cell({r: R, c: C});
            if (!ws[cellAddr]) ws[cellAddr] = {};
            ws[cellAddr].s = {...ws[cellAddr].s, border: borderStyle};  // 显式设置边框‌:ml-citation{ref="4,8" data="citationList"}
        }
    }
    return ws
};
//字符串转ArrayBuffer
const s2ab = (s) => {
    const buf = new ArrayBuffer(s.length);
    const view = new Uint8Array(buf);
    for (let i = 0; i < s.length; i++) {
        view[i] = s.charCodeAt(i) & 0xff;
    }
    return buf;
};

/**
 *导出 复杂表格  自定义表头格式  多级表头
 *可参考 正常性统计-正常性统计
 *参数1:表格表头数据       tableHeader
 *参数2:表格数据          list
 *参数3:多级表头 合集prop  filterVal
 *参数4:导出文件名         name
 *参数5:合并单元格数据      merges
 */
// 自己处理数据为 二维数组 格式 自定义表头/内容
export function complexTableCustomStyle(tableHeader, list, filterVal, name, merges) {
    const data = [...formatJson(filterVal, list)]
    data.unshift(tableHeader[1]);
    data.unshift(tableHeader[0]);
    let wb = XLSX.utils.book_new() //新建工作簿
    let ws = XLSX.utils.aoa_to_sheet(data) //data 二维数组-----将二维数组转换为工作表对象,自动处理数据类型
    if (merges.length > 0) { //处理合并单元格 这里手动写二维数组
        if (!ws['!merges']) ws['!merges'] = [];
        merges.forEach(item => {
            ws['!merges'].push(XLSX.utils.decode_range(item))
        })
    }
    XLSX.utils.book_append_sheet(wb, ws, "Sheet1")  //将工作表插入到工作簿中
    mergeCell(ws)
    setPubExcel(ws);
    const wBout = XLSX_STYLE.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'});
    FileSaver.saveAs(new Blob([s2ab(wBout)], {type: 'application/octet-stream;charset=utf-8"'}), `${name}`)
}

/**
 ************************************** 导出 end ************************************************
 */
表格ui图:

导出结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值