详解如何在Vue项目中导出Excel


Posted in Javascript onApril 19, 2019

Excel 导出

Excel 的导入导出都是依赖于js-xlsx来实现的。

在 js-xlsx的基础上又封装了Export2Excel.js来方便导出数据。

使用

由于 Export2Excel不仅依赖js-xlsx还依赖file-saver和script-loader。

所以你先需要安装如下命令:

npm install xlsx file-saver -S
npm install script-loader -S -D

 由于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来方便导出数据。

目录如下

详解如何在Vue项目中导出Excel

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(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;
}

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: 1432179778664,
     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: 2864,
     platforms: ["a-platform"],
     reviewer: "Sandra",
     status: "published",
     title: "O20190407135010000000001",
     type: "CN"
    },
    {
     timestamp: 1432179778664,
     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: 2864,
     platforms: ["a-platform"],
     reviewer: "Sandra",
     status: "published",
     title: "O20190407135010000000001",
     type: "CN"
    },
    {
     timestamp: 1432179778664,
     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: 2864,
     platforms: ["a-platform"],
     reviewer: "Sandra",
     status: "published",
     title: "O20190407135010000000001",
     type: "CN"
    },
    {
     timestamp: 1432179778664,
     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: 2864,
     platforms: ["a-platform"],
     reviewer: "Sandra",
     status: "published",
     title: "O20190407135010000000001",
     type: "CN"
    },
    {
     timestamp: 1432179778664,
     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: 2864,
     platforms: ["a-platform"],
     reviewer: "Sandra",
     status: "published",
     title: "O20190407135010000000001",
     type: "CN"
    },
    {
     timestamp: 1432179778664,
     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: 2864,
     platforms: ["a-platform"],
     reviewer: "Sandra",
     status: "published",
     title: "O20190407135010000000001",
     type: "CN"
    },
    {
     timestamp: 1432179778664,
     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: 2864,
     platforms: ["a-platform"],
     reviewer: "Sandra",
     status: "published",
     title: "O20190407135010000000001",
     type: "CN"
    },
    {
     timestamp: 1432179778664,
     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: 2864,
     platforms: ["a-platform"],
     reviewer: "Sandra",
     status: "published",
     title: "O20190407135010000000001",
     type: "CN"
    },
    {
     timestamp: 1432179778664,
     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: 2864,
     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;
  }
 }
}

效果图如下

详解如何在Vue项目中导出Excel

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

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

Javascript 相关文章推荐
jquery中防刷IP流量软件影响统计的一点对策
Jul 10 Javascript
javascript面向对象编程代码
Dec 19 Javascript
jQuery的attr与prop使用介绍
Oct 10 Javascript
jquery+json实现数据二级联动的方法
Nov 28 Javascript
BootStrap日期控件在模态框中选择时间下拉菜单无效的原因及解决办法(火狐下不能点击)
Aug 18 Javascript
把多个JavaScript函数绑定到onload事件处理函数上的方法
Sep 04 Javascript
Javascript中常见的逻辑题和解决方法
Sep 17 Javascript
js遮罩效果制作弹出注册界面效果
Jan 25 Javascript
浅谈Vue.js
Mar 02 Javascript
JS条形码(一维码)插件JsBarcode用法详解【编码类型、参数、属性】
Apr 19 Javascript
layui的table中显示图片方法
Aug 17 Javascript
原生js实现无缝轮播图
Jan 11 Javascript
vue cli使用融云实现聊天功能的实例代码
Apr 19 #Javascript
详解vue中使用微信jssdk
Apr 19 #Javascript
vue router导航守卫(router.beforeEach())的使用详解
Apr 19 #Javascript
this.$toast() 了解一下?
Apr 18 #Javascript
Vue-input框checkbox强制刷新问题
Apr 18 #Javascript
vue axios封装及API统一管理的方法
Apr 18 #Javascript
Vue组件系列开发之模态框
Apr 18 #Javascript
You might like
PHP获取短链接跳转后的真实地址和响应头信息的方法
2014/07/25 PHP
PHP ADODB实现事务处理功能示例
2018/05/25 PHP
php输出控制函数和输出函数生成静态页面
2019/06/27 PHP
jquery 弹出层实现代码
2009/10/30 Javascript
JS图片无缝、平滑滚动代码
2014/03/11 Javascript
浅谈Javascript中深复制
2014/12/01 Javascript
jquery实现增加删除行的方法
2015/02/03 Javascript
JavaScript实现的伸展收缩型菜单代码
2015/10/14 Javascript
在线引用最新jquery文件的实现方法
2016/08/26 Javascript
jQuery插件FusionCharts绘制的3D环饼图效果示例【附demo源码】
2017/04/02 jQuery
基于Jquery Ajax type的4种类型(详解)
2017/08/02 jQuery
解决layui上传文件提示上传异常,实际文件已经上传成功的问题
2018/08/19 Javascript
VUE引入第三方js包及调用方法讲解
2019/03/01 Javascript
element-ui 弹窗组件封装的步骤
2021/01/22 Javascript
[46:43]DOTA2上海特级锦标赛主赛事日 - 1 胜者组第一轮#2LGD VS MVP.Phx第二局
2016/03/02 DOTA
[01:12:53]完美世界DOTA2联赛PWL S2 Forest vs SZ 第一场 11.25
2020/11/26 DOTA
Python Web框架Flask信号机制(signals)介绍
2015/01/01 Python
深入分析python数据挖掘 Json结构分析
2018/04/21 Python
Django REST framework视图的用法
2019/01/16 Python
python远程连接MySQL数据库
2019/04/19 Python
Python3+Appium安装使用教程
2019/07/05 Python
简单了解python gevent 协程使用及作用
2019/07/22 Python
python实现输出一个序列的所有子序列示例
2019/11/18 Python
python清空命令行方式
2020/01/13 Python
Python 合并拼接字符串的方法
2020/07/28 Python
谷歌浏览器小字体处理方案即12px以下字体
2013/12/17 HTML / CSS
浅谈amaze-ui中datepicker和datetimepicker注意的几点
2020/08/21 HTML / CSS
迪卡侬荷兰官网:Decathlon荷兰
2017/10/29 全球购物
eDreams德国:南欧领先的在线旅游公司
2020/12/07 全球购物
2014政务公开实施方案
2014/02/19 职场文书
小学新学期寄语
2014/04/02 职场文书
中国文明网向国旗敬礼寄语大全
2014/09/27 职场文书
业务内勤岗位职责
2015/04/13 职场文书
班委竞选稿范文
2015/11/21 职场文书
Jupyter Notebook内使用argparse报错的解决方案
2021/06/03 Python
mysql查看表结构的三种方法总结
2022/07/07 MySQL