详解如何在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 相关文章推荐
javascript 火狐(firefox)不显示本地图片问题解决
Jul 05 Javascript
瀑布流布局并自动加载实现代码
Mar 12 Javascript
文字不间断滚动(上下左右)实例代码
Apr 21 Javascript
JavaScript实现弹出子窗口并传值给父窗口
Dec 18 Javascript
使用JavaScript获取地址栏参数的方法
Dec 19 Javascript
WordPress中利用AJAX技术进行评论提交的实现示例
Jan 12 Javascript
微信小程序 删除项目工程实现步骤
Nov 10 Javascript
Bootstrap Modal对话框如何在关闭时触发事件
Dec 02 Javascript
Bootstrap整体框架之JavaScript插件架构
Dec 15 Javascript
傻瓜式解读koa中间件处理模块koa-compose的使用
Oct 30 Javascript
解决Vue中使用keepAlive不缓存问题
Aug 04 Javascript
一起来看看Vue的核心原理剖析
Mar 24 Vue.js
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
高分R级DC动画剧《哈莉·奎茵》第二季正式预告首发
2020/04/09 欧美动漫
用PHP和ACCESS写聊天室(七)
2006/10/09 PHP
PHP操作数组的一些函数整理介绍
2011/07/17 PHP
php无限分类且支持输出树状图的详细介绍
2013/06/19 PHP
一个漂亮的php验证码类(分享)
2013/08/06 PHP
PHP/HTML混写的四种方式总结
2017/02/27 PHP
深入理解PHP+Mysql分布式事务与解决方案
2020/12/03 PHP
基于JavaScript自定义构造函数的详解说明
2013/04/24 Javascript
深入理解javascript动态插入技术
2013/11/12 Javascript
二叉树的非递归后序遍历算法实例详解
2014/02/07 Javascript
DOM 高级编程
2015/05/06 Javascript
小议JavaScript中Generator和Iterator的使用
2015/07/29 Javascript
JQuery的attr 与 val区别
2016/06/12 Javascript
JS实现图片预加载之无序预加载功能代码
2017/05/12 Javascript
JS验证码实现代码
2017/09/14 Javascript
Nodejs连接mysql并实现增、删、改、查操作的方法详解
2018/01/04 NodeJs
浅谈Vue下使用百度地图的简易方法
2018/03/23 Javascript
JQuery特殊效果和链式调用操作示例
2019/05/13 jQuery
微信小程序实现拍照画布指定区域生成图片
2019/07/18 Javascript
原生js实现点击轮播切换图片
2020/02/11 Javascript
django实现分页的方法
2015/05/26 Python
通过实例浅析Python对比C语言的编程思想差异
2015/08/30 Python
python实时分析日志的一个小脚本分享
2017/05/07 Python
Python并发之多进程的方法实例代码
2018/08/15 Python
python接口自动化测试之接口数据依赖的实现方法
2019/04/26 Python
使用Python的turtle模块画国旗
2019/09/24 Python
使用pyshp包进行shapefile文件修改的例子
2019/12/06 Python
HTML5和CSS3让网页设计提升到下一个高度
2009/08/14 HTML / CSS
配置管理计划的主要内容有哪些
2014/06/20 面试题
机械设计毕业生自荐信
2014/02/02 职场文书
环境卫生标语
2014/06/09 职场文书
党支部三会一课计划
2014/09/24 职场文书
2015共产党员公开承诺书
2015/01/22 职场文书
辩论赛新闻稿
2015/07/17 职场文书
小学班主任工作随笔
2015/08/15 职场文书
ORACLE数据库应用开发的三十个注意事项
2021/06/07 Oracle