视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
详解如何在Vue项目中导出Excel
2020-11-27 21:58:32 责编:小采
文档


 由于js-xlsx体积还是很大的,导出功能也不是一个非常常用的功能,所以使用的时候建议使用懒加载。使用方法如下:

import('@/vendor/Export2Excel').then(excel => {
 excel.export_json_to_excel({
 header: tHeader, //表头 必填
 data, //具体数据 必填
 filename: 'excel-list', //非必填, 导出文件的名字
 autoWidth: true, //非必填, 导出文件的排列方式
 bookType: 'xlsx' //非必填, 导出文件的格式
 })
})

注意

在v3.9.1+以后的版本中移除了对 Bolb 的兼容性代码,如果你还需要兼容很低版本的浏览器可以手动引入blob-polyfill进行兼容。

参数

参数 说明 类型 可选值 默认值
header 导出数据的表头 Array / []
data 导出的具体数据 Array / []
filename 导出文件名 String / excel-list
autoWidth 单元格是否要自适应宽度 Boolean true / false true
bookType 导出文件类型 String xlsx, csv, txt, more xlsx

项目实战

使用脚手架搭建出基本项目雏形,这时候在src目录下新建一个vendor(文件名自己定义)文件夹,新建一个Export2Excel.js文件,这个文件里面在js-xlsx的基础上又封装了Export2Excel.js来方便导出数据。

目录如下

Export2Excel.js代码如下

require('script-loader!file-saver');
import XLSX from 'xlsx'

function generateArray(table) {
 var out = [];
 var rows = table.querySelectorAll('tr');
 var ranges = [];
 for (var R = 0; R < rows.length; ++R) {
 var outRow = [];
 var row = rows[R];
 var columns = row.querySelectorAll('td');
 for (var C = 0; C < columns.length; ++C) {
 var cell = columns[C];
 var colspan = cell.getAttribute('colspan');
 var rowspan = cell.getAttribute('rowspan');
 var cellValue = cell.innerText;
 if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue;

 //Skip ranges
 ranges.forEach(function (range) {
 if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) {
 for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null);
 }
 });

 //Handle Row Span
 if (rowspan || colspan) {
 rowspan = rowspan || 1;
 colspan = colspan || 1;
 ranges.push({
 s: {
 r: R,
 c: outRow.length
 },
 e: {
 r: R + rowspan - 1,
 c: outRow.length + colspan - 1
 }
 });
 };

 //Handle Value
 outRow.push(cellValue !== "" ? cellValue : null);

 //Handle Colspan
 if (colspan)
 for (var k = 0; k < colspan - 1; ++k) outRow.push(null);
 }
 out.push(outRow);
 }
 return [out, ranges];
};

function datenum(v, date1904) {
 if (date1904) v += 1462;
 var epoch = Date.parse(v);
 return (epoch - new Date(Date.UTC(19, 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;
}

export function export_table_to_excel(id) {
 var theTable = document.getElementById(id);
 var oo = generateArray(theTable);
 var ranges = oo[1];

 /* original data */
 var data = oo[0];
 var ws_name = "SheetJS";

 var wb = new Workbook(),
 ws = sheet_from_array_of_arrays(data);

 /* add ranges to worksheet */
 // ws['!cols'] = ['apple', 'banan'];
 ws['!merges'] = ranges;

 /* add worksheet to workbook */
 wb.SheetNames.push(ws_name);
 wb.Sheets[ws_name] = ws;

 var wbout = XLSX.write(wb, {
 bookType: 'xlsx',
 bookSST: false,
 type: 'binary'
 });

 saveAs(new Blob([s2ab(wbout)], {
 type: "application/octet-stream"
 }), "test.xlsx")
}

export function export_json_to_excel({
 multiHeader = [],
 header,
 data,
 filename,
 merges = [],
 autoWidth = true,
 bookType = 'xlsx'
} = {}) {
 /* original data */
 filename = filename || 'excel-list'
 data = [...data]
 data.unshift(header);

 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': 10
 };
 }
 /*再判断是否为中文*/
 else if (val.toString().charCodeAt(0) > 255) {
 return {
 'wch': val.toString().length * 2
 };
 } else {
 return {
 'wch': val.toString().length
 };
 }
 }))
 /*以第一行为初始值*/
 let result = colWidth[0];
 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 wbout = XLSX.write(wb, {
 bookType: bookType,
 bookSST: false,
 type: 'binary'
 });
 saveAs(new Blob([s2ab(wbout)], {
 type: "application/octet-stream"
 }), `${filename}.${bookType}`);
}

新建一个exportExcel.vue模板用于导出Excel表格,使用代码如下

<template>
 <div class="exportExcel">
 <div class="excel-header">
 <!--导出文件名称-->
 <div class="filename">
 <label class="radio-label" style="padding-left:0;">Filename:</label>
 <el-input
 v-model="filename"
 placeholder="请输入导出文件名"
 style="width:340px;"
 prefix-icon="el-icon-document" />
 </div>
 <!--设置表格导出的宽度是否自动-->
 <div class="autoWidth">
 <label class="radio-label">Cell Auto-Width:</label>
 <el-radio-group v-model="autoWidth">
 <el-radio :label="true" border>True</el-radio>
 <el-radio :label="false" border>False</el-radio>
 </el-radio-group>
 </div>
 <!--导出文件后缀类型-->
 <div class="bookType">
 <label class="radio-label">Book Type:</label>
 <el-select v-model="bookType" style="width:120px;">
 <el-option v-for="item in options" :key="item" :label="item" :value="item"/>
 </el-select>
 </div>
 <!--导出文件-->
 <div class="download">
 <el-button
 :loading="downloadLoading"
 type="primary"
 icon="document"
 @click="handleDownload">export Excel</el-button>
 </div>
 </div>

 <el-table
 v-loading="listLoading"
 :data="list"
 element-loading-text="拼命加载中"
 border
 fit
 highlight-current-row
 height="390px"
 >
 <el-table-column align="center" label="序号" width="95">
 <template slot-scope="scope">{{ scope.$index }}</template>
 </el-table-column>
 <el-table-column label="订单号" width="230">
 <template slot-scope="scope">{{ scope.row.title }}</template>
 </el-table-column>
 <el-table-column label="菜品" align="center">
 <template slot-scope="scope">{{ scope.row.foods }}</template>
 </el-table-column>
 <el-table-column label="收银员" width="110" align="center">
 <template slot-scope="scope">
 <el-tag>{{ scope.row.author }}</el-tag>
 </template>
 </el-table-column>
 <el-table-column label="金额" width="115" align="center">
 <template slot-scope="scope">{{ scope.row.pageviews }}</template>
 </el-table-column>
 <el-table-column align="center" label="时间" width="220">
 <template slot-scope="scope">
 <i class="el-icon-time"/>
 <span>{{ scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
 </template>
 </el-table-column>
 </el-table>
 </div>
</template>

export default {
 name: "exportExcelDialog",
 data() {
 return {
 // 列表内容
 list: null,
 // loding窗口状态
 listLoading: true,
 // 下载loding窗口状态
 downloadLoading: false,
 // 导出文件名称
 filename: "",
 // 导出表格宽度是否auto
 autoWidth: true,
 // 导出文件格式
 bookType: "xlsx",
 // 默认导出文件后缀类型
 options: ["xlsx", "csv", "txt"]
 };
 },
 methods: {
 // 导出Excel表格
 handleDownload() {
 this.downloadLoading = true;
 // 懒加载该用法
 import("@/vendor/Export2Excel").then(excel => {
 // 设置导出表格的头部
 const tHeader = ["序号", "订单号", "菜品", "收银员", "金额", "时间"];
 // 设置要导出的属性
 const filterVal = [
 "id",
 "title",
 "foods",
 "author",
 "pageviews",
 "display_time"
 ];
 // 获取当前展示的表格数据
 const list = this.list;
 // 将要导出的数据进行一个过滤
 const data = this.formatJson(filterVal, list);
 // 调用我们封装好的方法进行导出Excel
 excel.export_json_to_excel({
 // 导出的头部
 header: tHeader,
 // 导出的内容
 data,
 // 导出的文件名称
 filename: this.filename,
 // 导出的表格宽度是否自动
 autoWidth: this.autoWidth,
 // 导出文件的后缀类型
 bookType: this.bookType
 });
 this.downloadLoading = false;
 });
 },
 // 对要导出的内容进行过滤
 formatJson(filterVal, jsonData) {
 return jsonData.map(v =>
 filterVal.map(j => {
 if (j === "timestamp") {
 return this.parseTime(v[j]);
 } else {
 return v[j];
 }
 })
 );
 },
 // 过滤时间
 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()
 };
 const timeStr = 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;
 });
 return timeStr;
 }
 },
 mounted() {
 // 模拟获取数据
 setTimeout(() => {
 this.list = [
 {
 timestamp: 14321797786,
 author: "Charles",
 comment_disabled: true,
 content_short: "mock data",
 display_time: "1994-05-25 23:37:25",
 foods: "鸡翅、萝卜、牛肉、红烧大闸蟹、红烧鸡翅",
 id: 1,
 image_uri:
 "https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3",
 importance: 3,
 pageviews: 28,
 platforms: ["a-platform"],
 reviewer: "Sandra",
 status: "published",
 title: "O20190407135010000000001",
 type: "CN"
 },
 {
 timestamp: 14321797786,
 author: "Charles",
 comment_disabled: true,
 content_short: "mock data",
 display_time: "1994-05-25 23:37:25",
 foods: "鸡翅、萝卜、牛肉、红烧大闸蟹、红烧鸡翅",
 id: 1,
 image_uri:
 "https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3",
 importance: 3,
 pageviews: 28,
 platforms: ["a-platform"],
 reviewer: "Sandra",
 status: "published",
 title: "O20190407135010000000001",
 type: "CN"
 },
 {
 timestamp: 14321797786,
 author: "Charles",
 comment_disabled: true,
 content_short: "mock data",
 display_time: "1994-05-25 23:37:25",
 foods: "鸡翅、萝卜、牛肉、红烧大闸蟹、红烧鸡翅",
 id: 1,
 image_uri:
 "https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3",
 importance: 3,
 pageviews: 28,
 platforms: ["a-platform"],
 reviewer: "Sandra",
 status: "published",
 title: "O20190407135010000000001",
 type: "CN"
 },
 {
 timestamp: 14321797786,
 author: "Charles",
 comment_disabled: true,
 content_short: "mock data",
 display_time: "1994-05-25 23:37:25",
 foods: "鸡翅、萝卜、牛肉、红烧大闸蟹、红烧鸡翅",
 id: 1,
 image_uri:
 "https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3",
 importance: 3,
 pageviews: 28,
 platforms: ["a-platform"],
 reviewer: "Sandra",
 status: "published",
 title: "O20190407135010000000001",
 type: "CN"
 },
 {
 timestamp: 14321797786,
 author: "Charles",
 comment_disabled: true,
 content_short: "mock data",
 display_time: "1994-05-25 23:37:25",
 foods: "鸡翅、萝卜、牛肉、红烧大闸蟹、红烧鸡翅",
 id: 1,
 image_uri:
 "https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3",
 importance: 3,
 pageviews: 28,
 platforms: ["a-platform"],
 reviewer: "Sandra",
 status: "published",
 title: "O20190407135010000000001",
 type: "CN"
 },
 {
 timestamp: 14321797786,
 author: "Charles",
 comment_disabled: true,
 content_short: "mock data",
 display_time: "1994-05-25 23:37:25",
 foods: "鸡翅、萝卜、牛肉、红烧大闸蟹、红烧鸡翅",
 id: 1,
 image_uri:
 "https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3",
 importance: 3,
 pageviews: 28,
 platforms: ["a-platform"],
 reviewer: "Sandra",
 status: "published",
 title: "O20190407135010000000001",
 type: "CN"
 },
 {
 timestamp: 14321797786,
 author: "Charles",
 comment_disabled: true,
 content_short: "mock data",
 display_time: "1994-05-25 23:37:25",
 foods: "鸡翅、萝卜、牛肉、红烧大闸蟹、红烧鸡翅",
 id: 1,
 image_uri:
 "https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3",
 importance: 3,
 pageviews: 28,
 platforms: ["a-platform"],
 reviewer: "Sandra",
 status: "published",
 title: "O20190407135010000000001",
 type: "CN"
 },
 {
 timestamp: 14321797786,
 author: "Charles",
 comment_disabled: true,
 content_short: "mock data",
 display_time: "1994-05-25 23:37:25",
 foods: "鸡翅、萝卜、牛肉、红烧大闸蟹、红烧鸡翅",
 id: 1,
 image_uri:
 "https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3",
 importance: 3,
 pageviews: 28,
 platforms: ["a-platform"],
 reviewer: "Sandra",
 status: "published",
 title: "O20190407135010000000001",
 type: "CN"
 },
 {
 timestamp: 14321797786,
 author: "Charles",
 comment_disabled: true,
 content_short: "mock data",
 display_time: "1994-05-25 23:37:25",
 foods: "鸡翅、萝卜、牛肉、红烧大闸蟹、红烧鸡翅",
 id: 1,
 image_uri:
 "https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3",
 importance: 3,
 pageviews: 28,
 platforms: ["a-platform"],
 reviewer: "Sandra",
 status: "published",
 title: "O20190407135010000000001",
 type: "CN"
 }
 ];
 this.listLoading = false;
 }, 2000);
 },
 filters: {
 // 过滤时间
 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()
 };
 const timeStr = 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;
 });
 return timeStr;
 }
 }
}

效果图如下

用法都是看GitHub开源项目的和博客的,自己本身还没有二次封装这样内容的实力,欢迎大佬提出宝贵的意见。

以上所述是小编给大家介绍的如何在Vue项目中导出Excel详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

下载本文
显示全文
专题