vue导出excel并修改样式
1.首先安装以下三个安装包
npm install --save xlsx(修改样式需要下载npm install --save xlsx-style)
npm install -S file-saver
npm install -D script-loader
注意:如果安装了npm install --save xlsx-style
会报错:This relative module was not found: ./cptable in ./node_modules/xlsx-style@0.8.13@xlsx-style/dist/cpexcel.js
可以直接修改源码:
在\node_modules\xlsx-style\dist\cpexcel.js 807行 的 var cpt = require(’./cpt’ + ‘able’); 改成 var cpt = cptable;
也可以在项目vue.config.js 文件中添加
module.exports = { lintOnSave: false, css: { loaderOptions: { sass: { data: `@import "~@/styles/variables.scss";` } } }, chainWebpack: config => { //在 chainWebpack 添加下面的一段代码 config.externals({ "./cptable": "var cptable" });** }, devServer: {} };
- 需要下载一个Blob.js (放在src 目录下)
- 新建一个Export2Excel.js
//这是从网上的,改了一点点 Export2Excel.js /* eslint-disable */ /* eslint-disable */ require("script-loader!file-saver"); import XLSX from "xlsx-style"; function datenum(v, date1904) { if (date1904) v += 1462; var epoch = Date.parse(v); return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000); } function sheet_from_array_of_arrays(data, opts) { var ws = {}; var range = { s: { c: 10000000, r: 10000000 }, e: { c: 0, r: 0 } }; for (var R = 0; R != data.length; ++R) { for (var C = 0; C != data[R].length; ++C) { if (range.s.r > R) range.s.r = R; if (range.s.c > C) range.s.c = C; if (range.e.r < R) range.e.r = R; if (range.e.c < C) range.e.c = C; var cell = { v: data[R][C] }; if (cell.v == null) continue; var cell_ref = XLSX.utils.encode_cell({ c: C, r: R }); if (typeof cell.v === "number") cell.t = "n"; else if (typeof cell.v === "boolean") cell.t = "b"; else if (cell.v instanceof Date) { cell.t = "n"; cell.z = XLSX.SSF._table[14]; cell.v = datenum(cell.v); } else cell.t = "s"; ws[cell_ref] = cell; } } if (range.s.c < 10000000) ws["!ref"] = XLSX.utils.encode_range(range); return ws; } function Workbook() { if (!(this instanceof Workbook)) return new Workbook(); this.SheetNames = []; this.Sheets = {}; } function s2ab(s) { var buf = new ArrayBuffer(s.length); var view = new Uint8Array(buf); for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff; return buf; } function export_json_to_excel({ title, multiHeader = [], header, data, filename, merges = [], autoWidth = true, bookType = "xlsx" } = {}) { // const merges = [`A1:${getCharCol(list.length - 2)}1`]; //合并单元格 /* original data */ filename = filename || "excel-list"; data = [...data]; data.unshift(header); if (title) { data.unshift(title); } for (let i = multiHeader.length - 1; i > -1; i--) { data.unshift(multiHeader[i]); } var ws_name = "SheetJS"; var wb = new Workbook(), ws = sheet_from_array_of_arrays(data); if (merges.length > 0) { if (!ws["!merges"]) ws["!merges"] = []; merges.forEach(item => { ws["!merges"].push(XLSX.utils.decode_range(item)); }); } if (autoWidth) { /*设置worksheet每列的最大宽度*/ const colWidth = data.map(row => row.map(val => { /*先判断是否为null/undefined*/ if (val == null) { return { wch: 13 }; } else if (val.toString().charCodeAt(0) > 255) { /*再判断是否为中文*/ return { wch: val.toString().length * 2 }; } else { return { wch: val.toString().length }; } }) ); // console.log(colWidth); /*以第一行为初始值*/ let result = colWidth[0]; colWidth[0][0]["wch"] = 13; // console.log(colWidth[0][0]["wch"]); for (let i = 1; i < colWidth.length; i++) { for (let j = 0; j < colWidth[i].length; j++) { if (result[j]["wch"] < colWidth[i][j]["wch"]) { result[j]["wch"] = colWidth[i][j]["wch"]; } } } ws["!cols"] = result; } /* add worksheet to workbook */ wb.SheetNames.push(ws_name); wb.Sheets[ws_name] = ws; var dataInfo = wb.Sheets[wb.SheetNames[0]]; // const borderAll = { // //单元格外侧框线 // top: { // style: "thin" // }, // bottom: { // style: "thin" // }, // left: { // style: "thin" // }, // right: { // style: "thin" // } // }; //给所以单元格加上边框 // for (var i in dataInfo) { // if (i == '!ref' || i == '!merges' || i == '!cols' || i == 'A1') { // } else { // dataInfo[i + ''].s = { // border: borderAll // } // } // } // 标题行 let arr = [ "A1", "B1", "C1", "D1", "E1", "F1", "G1", "H1", "I1", "J1", "K1", "L1", "M1", "N1", "O1", "P1", "Q1", "R1", "S1", "T1", "U1", "V1", "W1", "X1", "Y1", "Z1" ]; // arr.some(function(v) { // let a = merges[0].split(":"); // if (v == a[1]) { // dataInfo[v].s = {}; // return true; // } else { // dataInfo[v].s = {}; // } // }); //设置主标题样式 let style = { font: { // name: "宋体", // sz: 18, color: { rgb: "000000" }, bold: true // italic: false, // underline: false }, alignment: { horizontal: "center", vertical: "center" } // fill: { // fgColor: {rgb: "008000"}, // }, }; // dataInfo["B1"].s = style; // dataInfo["A1"].s = style; //excel标题样式 for (var i = 0; i < header.length; i++) { dataInfo[arr[i]].s = style; } var wbout = XLSX.write(wb, { bookType: bookType, bookSST: false, type: "binary" }); saveAs( new Blob([s2ab(wbout)], { type: "application/octet-stream" }), `${filename}.${bookType}` ); } function toExportExcel(tHeader, data, filename) { import("@/excel/Export2Excel").then(excel => { //表头对应字段 excel.export_json_to_excel({ header: tHeader, data: data, filename: filename, autoWidth: true, bookType: "xlsx" }); }); } export { toExportExcel, export_json_to_excel };
//util.js import "@/excel/Blob"; export { json2excel, getCharCol, formatJson }; // function parseTime(time, cFormat) { // if (arguments.length === 0) { // return null; // } // const format = cFormat || "{y}-{m}-{d} {h}:{i}:{s}"; // let date; // if (typeof time === "object") { // date = time; // } else { // if (typeof time === "string" && /^[0-9]+$/.test(time)) { // time = parseInt(time); // } // if (typeof time === "number" && time.toString().length === 10) { // time = time * 1000; // } // date = new Date(time); // } // const formatObj = { // y: date.getFullYear(), // m: date.getMonth() + 1, // d: date.getDate(), // h: date.getHours(), // i: date.getMinutes(), // s: date.getSeconds(), // a: date.getDay() // }; // // eslint-disable-next-line // const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { // let value = formatObj[key]; // // Note: getDay() returns 0 on Sunday // if (key === "a") { // return ["日", "一", "二", "三", "四", "五", "六"][value]; // } // if (result.length > 0 && value < 10) { // value = "0" + value; // } // return value || 0; // }); // // eslint-disable-next-line // return time_str; // } function json2excel(tableJson, filenames, autowidth, bookTypes) { import("@/excel/Export2Excel").then(excel => { var tHeader = []; var dataArr = []; var sheetnames = []; for (var i in tableJson) { tHeader.push(tableJson[i].tHeader); dataArr.push(formatJson(tableJson[i].filterVal, tableJson[i].tableDatas)); sheetnames.push(tableJson[i].sheetName); } excel.export_json_to_excel({ header: tHeader, data: dataArr, sheetname: sheetnames, filename: filenames, autoWidth: autowidth, bookType: bookTypes }); }); } // 数据过滤,时间过滤 function formatJson(filterVal, jsonData) { return jsonData.map(v => filterVal.map(j => { if (j === "timestamp") { return parseTime(v[j]); } else { return v[j]; } }) ); } // 获取26个英文字母用来表示excel的列 function getCharCol(n) { for (var i = 0; i < this.list.length; i++) { this.list[i].showActive = false; if (index == i) { this.list[index].showActive = true; } } let temCol = "", s = "", m = 0; while (n > 0) { m = (n % 26) + 1; s = String.fromCharCode(m + 64) + s; n = (n - m) / 26; } return s; }
用法
<div @click="exportExcel">下载短信模板</div>
import { formatJson } from "@/util.js"; import { toExportExcel } from "@/excel/Export2Excel"; export default { data() { return { //表格的数据 list: [ { name: "蓝叶子", phone: 18955191234, content: "第一个为前置条件,最后一个为预期结果,需要带相应关键字,第一个为前置条件,最后一个为预期结果" }, { name: "蓝叶子", phone: 18955191234, content: "第一个为前置条件,最后一个为预期结果,需要带相应关键字" }, { name: "蓝叶子", phone: "18955191234", content: "第一个为前置条件,最后一个为预期结果,需要带相应关键字,zhenhgdsdfsff" }, { name: "蓝叶子", phone: 18955191234, content: "第一个为前置条件,最后一个为预期结果,需要带相应关键字" }, { name: "蓝叶子", phone: "18955191234", content: "第一个为前置条件,最后一个为预期结果,需要带相应关键字,zhenhgdsdfsff" }, { name: "蓝叶子", phone: 18955191234, content: "第一个为前置条件,最后一个为预期结果,需要带相应关键字" }, { name: "蓝叶子", phone: "18955191234", content: "第一个为前置条件,最后一个为预期结果,需要带相应关键字,zhenhgdsdfsff" } ] }; }, methods: { exportExcel() { const filterVal = []; const list = this.list.map((item, index) => { if (index === 0) { for (var k in item) { filterVal.push(k); } } return { name: item.name, phone: +item.phone, //转成number content: item.content }; }); const tHeader = ["姓名", "手机号", "内容"]; //表头 const data = formatJson(filterVal, list); const filename = "短信模板"; toExportExcel(tHeader, data, filename); } } };