工作中有大量用到table表格导出excel的场景,所以基于xlsx插件,做一个完整的表格下载流程;
1、下载插件 xlsx
xlsx插件支持 .xlsx
、.xls
和 .csv
格式
npm install xlsx --save
或者
yarn add xlsx
2、导入 xlsx并封装方法
在你的 JavaScript 文件中,你可以使用 CommonJS 模块语法或 ES6 模块语法来导入 xlsx
:
CommonJS 模块语法:
const XLSX = require('xlsx');
ES6 模块语法:
import * as XLSX from 'xlsx';
本次这里使用的ES6语法引入,并且创建一个utils文件夹 => excel.js文件,用于做公共方法,方便后面直接使用该方法,方法如下,可直接使用。
/* eslint-disable */
import XLSX from 'xlsx'
// 创建标签并添加点击事件:下载
function downloadFile (hrefUrl, filename) {
// 创建标签
let label = document.createElement('a')
// 获取下载的链接
label.href = hrefUrl
label.style.display = 'none'
// 下载后的文件名
label.download = filename
// 将指定的DOM类型的节点加到document.body的末尾
document.body.appendChild(label)
// 添加点击事件
label.click()
// 移除创建的标签
document.body.removeChild(label)
}
export function downloadFileByFileFlow (blobData, mimeTypeStr) {
let blob = new Blob([blobData.data], { type: mimeTypeStr })
// 创建下载连击
let hrefUrl = window.URL.createObjectURL(blob)
// 获取headers中的表名
let contentDisposition = blobData.headers['content-disposition']
let patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
let result = patt.exec(contentDisposition)
let filename = decodeURI(result[1])
downloadFile(hrefUrl, filename)
}
/** 导出当前页面的数据 (水位)
*
* @param {*} vm 导出的表格
* @param {*} type 1 2 1当前页 2所有数据
*/
export function downLoad (vm, type) {
if (type === 1) {
vm.$refs.table.exportCsv({
// vm.$store.state.value vm.$store.state.curPage 这个目前还没有在store中设置 后期会改动文件位置
filename: `${vm.cmp}-${vm.$store.state.value}第${vm.$store.state.curPage}页数据`,
columns: vm.columns.filter((col, index) => index >= 0)
})
}
}
// 设置导出的宽度
function auto_width (ws, data) {
/*set worksheet max width per col*/
const colWidth = data.map(row => row.map(val => {
/*if null/undefined*/
if (val == null) {
return {'wch': 10}
} else {
// console.log('当前单元格的长度最大', val, val.toString().length);
// 防止数据过长导致需要滑动距离过长
if (val.toString().length > 400) {
return {'wch': val.toString().length / 40}
} else {
return {'wch': 30}
}
}
}))
/*start in the first row*/
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
}
function json_to_array (key, jsonData) {
return jsonData.map(v => key.map(j => { return v[j] }))
}
// fix data,return string
function fixdata (data) {
let o = ''
let l = 0
const w = 10240
for (; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)))
o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)))
return o
}
// get head from excel file,return array
function get_header_row (sheet) {
const headers = []
const range = XLSX.utils.decode_range(sheet['!ref'])
let C
const R = range.s.r /* start in the first row */
for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
var cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })] /* find the cell in the first row */
var hdr = 'UNKNOWN ' + C // <-- replace with your desired default
if (cell && cell.t) hdr = XLSX.utils.format_cell(cell)
headers.push(hdr)
}
return headers
}
export const export_table_to_excel = (id, filename) => {
const table = document.getElementById(id)
const wb = XLSX.utils.table_to_book(table)
XLSX.writeFile(wb, filename)
}
export const export_json_to_excel = ({data, key, title, filename, autoWidth}) => {
const wb = XLSX.utils.book_new()
data.unshift(title)
const ws = XLSX.utils.json_to_sheet(data, {header: key, skipHeader: true})
if(autoWidth){
const arr = json_to_array(key, data)
auto_width(ws, arr)
}
XLSX.utils.book_append_sheet(wb, ws, filename)
XLSX.writeFile(wb, filename + '.xlsx')
}
/**
* key 单元格key
* data 表格值
* title 单元格标题
* filename 文件名
* autoWidth 自动计算宽度
*/
export const export_array_to_excel = ({key, data, title, filename, autoWidth}) => {
const wb = XLSX.utils.book_new()
const arr = json_to_array(key, data)
arr.unshift(title)
const ws = XLSX.utils.aoa_to_sheet(arr)
if(autoWidth){
auto_width(ws, arr)
}
XLSX.utils.book_append_sheet(wb, ws, filename)
XLSX.writeFile(wb, filename + '.xlsx')
}
export const read = (data, type) => {
/* if type == 'base64' must fix data first */
// const fixedData = fixdata(data)
// const workbook = XLSX.read(btoa(fixedData), { type: 'base64' })
const workbook = XLSX.read(data, { type: type })
const firstSheetName = workbook.SheetNames[0]
const worksheet = workbook.Sheets[firstSheetName]
const header = get_header_row(worksheet)
const results = XLSX.utils.sheet_to_json(worksheet)
return {header, results}
}
3、vue文件中使用excel方法
<template>
<Button @click="exportExceptionData" size="small" icon="ios-thunderstorm-outline">导出表格</Button>
<Table v-if="exceptionAll.length !== 0" :columns="columnsException" :data="exceptionAll" />
</template>
<script>
import { export_array_to_excel } from '@/utils/excel.js' //引入方法
data () {
return {
exceptionAll: [], // table表格绑定的data数据,通过后端接口获取数据
// 准备导出的列信息,确保里面的key要和table表格中的column和data中的type或prop保持对应,否则导出的excel表格中某一列会为空
columnsException: [
{
title: '姓名',
key: 'name',
minWidth: 100,
sortable: true
},
{
title: '年龄',
key: 'age',
sortable: true,
minWidth: 100
},
{
title: '性别',
key: 'gender',
sortable: true,
minWidth: 100
}
]
}
},
methods: {
exportExceptionData () {
let downData = []
downData = JSON.parse(JSON.stringify(this.exceptionAll))
// 导出为xlsx格式,这个data可以对数据进行循环遍历成我们想要的格式的数据
let excelParams = {
title: [],
key: [],
data: [],
autoWidth: true,
filename: `测试表格文件名` //下载下来的文件名
}
// 这里需要把title和key添加到对应的excelParams,用于下载时一一对应数据(主要是excel的表头和每一列数据对应)
this.exceptionAll.forEach(item => {
excelParams.title.push(item.title)
excelParams.key.push(item.key)
})
// 最终确保导出的数组excelParams要有title和key,其余的无所谓:[{title: '姓名',key: ' name'},{title: '年龄',key: ' age'}]
export_array_to_excel(excelParams) //最后调用刚刚封装好的方法
}
}
</script>
最后就可以直接使用xlsx
插件直接导出excel了。
xlsx
插件非常强大,支持许多高级功能,如样式、公式、图表等。你可以在其 GitHub 仓库 中找到更多示例和文档。