vue 实现Excel 导出

article/2025/9/14 0:39:12

前言

  • 数据表格的导出,是实际开发的常见功能,前后端都可以实现表格导出,讲解自己在用的一种。

  • 获取数据源,可以通过后端接口实现,也可以利用分页查询的表格接口来实现。

  • 处理数据,对excel表格的表头(最上面一行)表格数据是一个二维数组对应起来的,表格文件名字。

  • 利用第三方包构建Excel,vue-element-admin 是提供了文档的,可以根据实际情况更改。

实现

官方文档

1.下包,在工具文件引入第三方工具包(构建Excel表格),体积大使用的时候使用懒加载

由于 Export2Excel不仅依赖js-xlsx还依赖file-saverscript-loader

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

新建文件在src/vendor/Export2Excel.js 代码如下

/* eslint-disable */
import { saveAs } from 'file-saver'
import * as 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.innerTextif (cellValue !== '' && cellValue == +cellValue) cellValue = +cellValue
​//Skip rangesranges.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 Spanif (rowspan || colspan) {rowspan = rowspan || 1colspan = colspan || 1ranges.push({s: {r: R,c: outRow.length},e: {r: R + rowspan - 1,c: outRow.length + colspan - 1}})}
​//Handle ValueoutRow.push(cellValue !== '' ? cellValue : null)
​//Handle Colspanif (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 += 1462var 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 = Rif (range.s.c > C) range.s.c = Cif (range.e.r < R) range.e.r = Rif (range.e.c < C) range.e.c = Cvar cell = {v: data[R][C]}if (cell.v == null) continuevar 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) & 0xffreturn 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}`)
}

2.来到需要导出的页面。加一个导出按钮

<el-buttontype="warning"plainicon="el-icon-download"size="mini"style="float: right; margin-right: 15px"@click="exportExcel">导出设备</el-button>
 

3.来到methods中处理数据,构建Excel表格

// 导出的点击事件exportExcel() {import('@/vendor/Export2Excel').then(async (excel) => {// 一次性查出所有数据const res = await eqfirinquire(this.pageInfo)console.log('导出数据', res.data.list)// 用一个数组接收const list = res.data.list
​// 准备中英文转换的数组const userRelations = {设备名称: 'deviceName',设备类型: 'equipmentType',序列号: 'deviceSerial',所属单位: 'company',在线状态: 'netStatus',设备状态: 'deviceStatus',设备id: 'deviceId'}
​// 要弄出一个表头,也就是弄到上面对应的中文const header = Object.keys(userRelations)
​// 弄出一个对应的内容(必须是二维数组)// 内容有多少个就要产生多少个一样的数组,所以用mapconst data = list.map((v) => {// 准备数组const arr = []// 遍历header(因为要保证表头有多少个才取出多少个属性)for (const key in userRelations) {// 得到英文keyconst enKey = userRelations[key]// 每一条数据构建都会通过这里  不需要替换就把这个注释掉,用下面的// 使用全部过滤器,枚举if (key === '在线状态') {arr.push(StateukeeperType(v[enKey]))} else {// 取出对应的值,加到数组里arr.push(v[enKey])}// 这个是你的表格里面没有像状态 0 1 (这是后端返回来的数据)不用替换成中文就直接用下面的// arr.push(v[enKey])}return arr})
​// 表头excel.export_json_to_excel({header, // 表头 必填data, // 具体数据 必填filename: '设备表', // Excel文件名字非必填autoWidth: true, // 是否自适应列宽非必填bookType: 'xlsx' // 格式非必填})})}

细节

我这里的数据来源是表格分页查询接口,第一次进到页面时会调用一次,会把总数给total,第二次就可以查出全部数据了,

如果在打包的过程中报一个为空的报错,追踪报错是在本地代码中的xlsx构建这一行,可能是vue3 和引入xlsx的问题,改一下引入方式就可以了。import * as XLSX from 'xlsx',报错如下图。

处理数据时有一个全局过滤器枚举的造作可以不用管,后期主页博客有,不需要状态转成中文就直接把上面注释掉,用下面的。直接复制要看一下

// 原来的引入方式可能会报错
// import XLSX from 'xlsx'
// 新的引入方式
import * as XLSX from 'xlsx'


 

总结:

经过这一趟流程下来相信你也对 vue 实现Excel 导出 有了初步的深刻印象,但在实际开发中我们遇到的情况肯定是不一样的,所以我们要理解它的原理,万变不离其宗。加油,打工人!

什么不足的地方请大家指出谢谢 -- 風过无痕


http://chatgpt.dhexx.cn/article/pg26yA17.shtml

相关文章

vue导出excel并修改样式

1.首先安装以下三个安装包 npm install --save xlsx(修改样式需要下载npm install --save xlsx-style)npm install -S file-savernpm install -D script-loader 注意&#xff1a;如果安装了npm install --save xlsx-style 会报错&#xff1a;This relative module was not fo…

springboot vue导出excel 使用easypoi

springboot vue导出excel 处理后端返回的文件流&#xff0c;下载成excl文件 vue <el-button class"el-icon-download" type"success" click"exportExcel()">导出</el-button>没封装axios exportExcel() {axios({url: 请求地址, …

Vue导出Excel表格信息

一、安装两个依赖包 npm install -S file-saver xlsxnpm install -D script-loader二、项目中新建一个文件夹 里面放置两个文件Blob.js和 Export2Excel.js。 同时注意Export2Excel里引用Blob的路径是否正确。 三、使用案例 3.1、使用注意事项 表头对应的键要和传过来的数据…

vue导出excel表

方法一&#xff1a;vue2.0 element UI 中 el-table 数据导出Excel 。https://blog.csdn.net/u010427666/article/details/79208145 方法二&#xff1a; 1.安装2个依赖包&#xff08;其实是3个&#xff09; npm install -S file-saver xlsxnpm install -D script-loader 2.在…

Vue导出Excel的实现方法与原理

摘要&#xff1a;本文将详细介绍前端Vue中导出Excel的方法&#xff0c;包括使用第三方库和纯前端实现两种方式。同时解释其原理&#xff0c;帮助读者了解如何在Vue项目中高效地导出Excel文件。 第三方库&#xff1a;exceljs exceljs是一款功能强大的JavaScript库&#xff0c;它…

Vue实现excel文件的导出功能(后端直接返回文件流)

✍️ 作者简介: 一个每天中午去打篮球和锻炼的前端开发。 &#x1f408;‍⬛ 两只猫&#x1f431;和一只狗的铲屎官&#x1f436; &#x1f9e3; 微博: GuoJ阝阝&#xff08;fu&#xff09; 文章目录 前言一、实现效果二、实现步骤1、添加导出按钮2、添加点击事件函数3、获取当…

vue导出excel表格(详细教程)

在开发的时候&#xff0c;会经常用的导出excel表格功能,刚好自己开发有遇到&#xff0c;就记录一下 一、安装vue-json-excel npm install vue-json-excel -S二、main.js中引入 import JsonExcel from vue-json-excel Vue.component(downloadExcel, JsonExcel)三、在代码中使…

Vue2中导出Excel

目录 方式一 &#xff1a;vue-json-excel 1、引入vue-json-excel 2、 main.js中全局注册 3、使用 4、效果图 ​​ 方式二&#xff1a;file-saver、xlsx、script-loader 1、引入依赖 2、下载并引入Blob.js和Export2Excel.js 3、使用 4、效果图 导出指定的记录 1、引…

内网建站 NAT穿透 局域网穿透

背景&#xff1a; 一直想搭建个人的博客&#xff0c;但是买云服务器一年动则几千少则几百&#xff0c;想到家里有一台空闲的笔记本&#xff0c;于是乎想到了内网穿透&#xff5e; 准备工作&#xff1a; 个人电脑一台&#xff0c;小蝴蝶内网穿透 步骤一&#xff1a; 搭建好内网博…

内网穿透是什么?

文章目录 内网穿透的目的内网穿透的阻碍如何实现知识点正向代理反向代理 参考&#xff1a; 内网穿透 知识点 内网穿透是什么&#xff0c;如何利用花生壳实现内网穿透 内容从网络上收集而来 内网穿透的目的 使得外网能够访问内网应用。 或者&#xff0c;使得 两个内网能够相互通…

内网穿透-把自己的电脑部署为公网可访问的服务器

推荐一款工具&#xff0c;能够把自己电脑上的项目暴露到公网上、把自己的项目展示给别人看看。 使用很方便&#xff0c;可免费&#xff08;有收费项目&#xff09;使用。 下载 工具叫做 cpolar &#xff0c;其下载地址为&#xff1a;https://i.cpolar.com/m/4GSo &#xff0c…

内网穿透技术有哪些(经验分享)

内网穿透技术&#xff1a;说到内网穿透&#xff0c;相信很多人肯定一知半解&#xff0c;到底什么是内网穿透呢&#xff01;什么情况下需要内网穿透呢&#xff01;接下来给大家简单的述说一下原理&#xff0c;内网穿透&#xff0c;也即 NAT 穿透&#xff0c;进行 NAT 穿透是为了…

可以实现内网穿透的几款工具

https://blog.csdn.net/qq_36468810/article/details/109219639 me批注&#xff1a;现在流行使用cpolar&#xff0c;极客工具&#xff0c;HTTPS安全的隧道穿透&#xff0c;用它来调试微信公众号&#xff0c;远程控制树梅派&#xff0c;超级方便。而且还是免费的。https://cpol…

浅谈内网穿透

内网穿透&#xff0c;也叫NAT穿透&#xff0c;进行NAT穿透是为了使具有某一个特定源ip地址和源端口号的数据包不被NAT设备屏蔽而正确路由到内网主机。 什么是【内网穿透】&#xff1f; 在当前的互联网环境中&#xff0c;由于IPv4的公网地址数量是有限的&#xff0c;无法给每一台…

内网穿透什么意思?内网穿透基础知识原理内网穿透服务器搭建可以干嘛服务器端口映射无需公网IP教程方法

内网穿透什么意思&#xff1f;内网穿透基础知识原理内网穿透服务器搭建可以干嘛服务器端口映射无需公网IP教程方法 什么是内网&#xff08;今天说点大家都能听得懂的&#xff01;&#xff01;&#xff01;&#xff09; 通常情况下&#xff0c;内网 可以简单的理解为路由器创建…

内网穿透的作用 免费内网穿透有哪些 可以用来干什么

相信有很多人都会被一个问题所困惑&#xff0c;我们在日常办公和生活中&#xff1b;一些内网访问的应用&#xff0c;如何让实现在任意外网进行链接访问呢&#xff1f;有人说可以用内网穿透 内网穿透具体是什么&#xff0c;原理是什么&#xff1b;今天我们用网云穿来做演示。内…

重启路由器可以换IP吗

想换IP有哪些方法可以实现&#xff1f;有时候IP被限制了&#xff0c;怎么换IP访问&#xff0c;重启路由器可以换IP吗&#xff1f;一般家庭的基于PPPOE拨号方式上网的,使用的是动态IP&#xff0c;可以更换IP&#xff0c;下面一起去看看如何重启路由器&#xff1a; 1、断电源重启…

矩阵切换器有哪些控制方式,有什么好处

矩阵切换器有哪些控制方式呢&#xff1f;矩阵切换器&#xff0c;可以使用网络控制&#xff0c;app控制&#xff0c;web等方式控制。 一、网络控制是指设备加一个网络模块使得在一个局域网内电脑进行控制。 二、app控制是指设备加一个app控制模块&#xff0c;使得手机&#xf…

vmware 静态ip上网 防止切换网络换ip

问题&#xff1a;因为电脑有的时候用公司wifi、手机热点、或家里的wifi进行上网。但要保证vmware虚拟机固定ip且能访问网络。 一、安装好虚拟后在菜单栏选择编辑→ 虚拟网络编辑器&#xff0c;打开虚拟网络编辑器对话框&#xff0c;选择Vmnet1 Net网络连接方式&#xff0c;随意…

手机如何远程连接服务器

所有VPS均同时支持MSTSC、VNC和手机远程控制&#xff0c;本篇为手机连接教程 0、首先下载安装APP微软的RD Celient 1、运行RD Celient &#xff0c;点击右上角的加号 2、然后在谈出的窗口选择Desktop来添加远程服务器地址 3、Host name or ip address这里填远程服务器的连接地址…