详解如何在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 获得选中文本内容的方法
Feb 15 Javascript
js实现div弹出层的方法
Nov 20 Javascript
JavaScript点击按钮后弹出透明浮动层的方法
May 11 Javascript
基于JavaScript实现简单的随机抽奖小程序
Jan 05 Javascript
js实现控制textarea输入字符串的个数,鼠标按下抬起判断输入字符数
Oct 25 Javascript
vue2实现可复用的轮播图carousel组件详解
Nov 27 Javascript
JS中promise化微信小程序api
Apr 12 Javascript
手动下载Chrome并解决puppeteer无法使用问题
Nov 12 Javascript
说说Vuex的getters属性的具体用法
Apr 15 Javascript
如何实现双向绑定mvvm的原理实现
May 28 Javascript
JavaScript中的相等操作符使用详解
Dec 21 Javascript
原生JS实现记忆翻牌游戏
Jul 31 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判断变量的函数
2012/04/24 PHP
php根据日期判断星座的函数分享
2014/02/13 PHP
php 5.6版本中编写一个PHP扩展的简单示例
2015/01/20 PHP
PHP使用token防止表单重复提交的方法
2016/04/07 PHP
php日期操作技巧小结
2016/06/25 PHP
PHP7匿名类的用法示例
2019/04/05 PHP
php和js实现根据子网掩码和ip计算子网功能示例
2019/11/09 PHP
js通过八个点 拖动改变div大小的实现方法
2014/03/05 Javascript
如何减少浏览器的reflow和repaint
2015/02/26 Javascript
Javascript中的匿名函数与封装介绍
2015/03/15 Javascript
JavaScript获取并更改input标签name属性的方法
2015/07/02 Javascript
PHP抓取HTTPS内容和错误处理的方法
2016/09/30 Javascript
jquery 标签 隔若干行加空白或者加虚线的方法
2016/12/07 Javascript
详解nodejs通过代理(proxy)发送http请求(request)
2017/09/22 NodeJs
Vue.js简易安装和快速入门(第二课)
2017/10/17 Javascript
vue2.x+webpack快速搭建前端项目框架详解
2017/11/30 Javascript
Vue 页面跳转不用router-link的实现代码
2018/04/12 Javascript
js实现轮播图的完整代码
2020/10/26 Javascript
vue表单验证你真的会了吗?vue表单验证(form)validate
2019/04/07 Javascript
浅谈Vue SSR中的Bundle的具有使用
2019/11/21 Javascript
vue项目查看vue版本及cli版本的实现方式
2020/10/24 Javascript
[02:17]快乐加倍!DOTA2食人魔魔法师至宝+迎霜节活动上线
2019/12/22 DOTA
python实现DNS正向查询、反向查询的例子
2014/04/25 Python
由Python运算π的值深入Python中科学计算的实现
2015/04/17 Python
python将一组数分成每3个一组的实例
2018/11/14 Python
Pycharm新建模板默认添加个人信息的实例
2019/07/15 Python
django的auth认证,authenticate和装饰器功能详解
2019/07/25 Python
python 哈希表实现简单python字典代码实例
2019/09/27 Python
基于pytorch 预训练的词向量用法详解
2020/01/06 Python
Python实现常见的几种加密算法(MD5,SHA-1,HMAC,DES/AES,RSA和ECC)
2020/05/09 Python
意大利独特而优质的家居用品:Fazzini
2018/12/05 全球购物
优良学风班总结材料
2014/02/08 职场文书
党员自我评价范文2015
2015/03/03 职场文书
2016元旦文艺汇演主持词
2015/07/06 职场文书
redis哨兵常用命令和监控示例详解
2021/05/27 Redis
Win10系统搭建ftp文件服务器详细教程
2022/08/05 Servers