楼主: feng21539
167 0

Vue3 + Element Plus 表格导出Excel 通用工具文档 [推广有奖]

  • 0关注
  • 0粉丝

等待验证会员

学前班

40%

还不是VIP/贵宾

-

威望
0
论坛币
0 个
通用积分
0
学术水平
0 点
热心指数
0 点
信用等级
0 点
经验
20 点
帖子
1
精华
0
在线时间
0 小时
注册时间
2018-10-18
最后登录
2018-10-18

楼主
feng21539 发表于 2025-12-11 18:47:40 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

一、工具简介

本工具基于 xlsx 库进行封装,专为 Vue3 与 Element Plus 技术栈设计,提供高效便捷的 Excel 数据导出功能。支持两种主要模式:「数组数据导出」(推荐使用)和「DOM 表格导出」(适用于存在分页或筛选逻辑的场景)。具备高度可配置性、良好的错误处理机制以及格式兼容能力。

xlsx

1.1 主要特性

  • 通用性强:可适配任意结构的表格组件,支持自定义表头内容、文件名称及工作表名称;
  • 操作简便:内置默认配置项,减少重复编码工作,支持自动提取表格列标题;
  • 稳定可靠:包含参数合法性校验与异常提示机制,有效避免数字格式被转为科学计数法(如手机号码等敏感字段);
  • 无额外依赖:采用原生方式实现文件下载流程,仅需引入核心库即可运行,不强制依赖其他插件。
el-table
file-saver

二、依赖安装

项目中使用该工具前,需先安装必要依赖包:

# 核心库
npm install xlsx --save

# (可选)若需使用 Element Plus 的消息提示功能,请确保已安装
npm install element-plus --save

三、文件目录结构

工具整体结构清晰,便于集成与维护:

src/
└── utils/
    └── exportExcel.js  # 核心封装文件

四、核心 API 使用说明

4.1 数组数据导出(推荐方式)

适用于导出前端完整持有的数据列表(不受当前页面显示范围限制),通过字段映射控制输出内容与表头显示名称。

exportExcel

函数定义

export const exportExcel = async (options) => {}

参数说明(options 对象)

参数名 类型 是否必传 默认值 说明
data Array - 原始数据数组,例如接口返回的完整用户列表或订单集合
headerMap Object - 字段映射关系对象,格式为 { key: '显示名' },用于指定导出字段及其在 Excel 中的列标题
sheetName String '数据表' 生成的工作表名称
fileName String '导出数据' 导出文件的基础名称,系统将自动附加时间戳以区分版本
withTimestamp Boolean true 是否在文件名后添加时间戳,设置为 false 可关闭此功能
el-table
data
{ 字段名: 显示名 }
withTimestamp

返回值

无实际返回值。调用后会自动触发浏览器的文件下载行为,并根据执行结果弹出相应提示信息。

Promise<void>

使用示例

import { exportExcel } from '@/utils/exportExcel'

// 模拟用户数据
const userList = [
  { name: '张三', age: 20, phone: 13800138000, email: 'zhangsan@test.com' },
  { name: '李四', age: 22, phone: 13900139000, email: 'lisi@test.com' }
]

// 执行导出操作
exportExcel({
  data: userList,
  headerMap: {
    name: '姓名',
    age: '年龄',
    phone: '手机号' // 仅导出这三个字段,email 将被忽略
  },
  fileName: '用户列表',
  sheetName: '2025年用户数据',
  withTimestamp: false // 禁用时间戳
})

4.2 DOM 表格内容导出

用于导出当前页面上已渲染的表格 DOM 内容,特别适合后端分页、前端仅展示部分记录的业务场景。

exportTableDom

函数定义

export const exportTableDom = async (options) => {}

参数说明(options 对象)

参数名 类型 是否必传 默认值 说明
ele String / HTMLElement - 目标表格的选择器字符串(如 #table-id)或直接传入 DOM 元素实例
sheetName String '当前页数据' Excel 工作表名称
fileName String '当前页数据' 导出文件名称
withTimestamp Boolean true 是否在文件名中加入时间戳
#export-table
tableRef.value.$el

返回值

无返回值。内部自动完成数据抓取、转换和文件下载流程。

Promise<void>

使用示例

import { exportTableDom } from '@/utils/exportExcel'
import { ref } from 'vue'

const orderTableRef = ref(null)

// 方法一:通过 CSS 选择器定位表格
exportTableDom({
  ele: '#order-table', // 需确保 el-table 设置了 id="order-table"
  fileName: '2025-12订单列表',
  sheetName: '12月订单'
})

// 方法二:通过 ref 引用获取 DOM 节点
exportTableDom({
  ele: orderTableRef.value.$el,
  fileName: '订单数据'
})

4.3 自动解析表格列头

支持从 el-table 组件的列配置中自动提取表头信息,动态生成字段映射关系,无需手动编写 headerMap,适用于希望简化配置流程的开发者。

getTableHeaderMap
el-table
headerMap

函数签名

export const getTableHeaderMap = (tableRef) => {}

参数说明

参数名 类型 是否必传 说明
tableRef Object el-table 的 ref 引用对象

返回值

类型 说明
Object 解析后的 headerMap,格式如下:
{ prop: label }

示例代码

import { exportExcel, getTableHeaderMap } from '@/utils/exportExcel'
import { ref } from 'vue'

const userTableRef = ref(null) // 对应 el-table 的 ref 绑定

// 自动解析表头并执行导出操作
const exportAutoHeader = () => {
    const headerMap = getTableHeaderMap(userTableRef.value)
    exportExcel({
        data: userList.value,
        headerMap,       // 使用自动解析的表头映射
        fileName: '用户列表'
    })
}

四、完整工具实现(exportExcel.js)

import XLSX from 'xlsx'
import { ElMessage } from 'element-plus'

/**
 * 通用 Excel 导出功能(支持数组数据)
 * @param {Object} options - 导出配置项
 * @param {Array} options.data - 源数据数组(必填)
 * @param {Object} options.headerMap - 表头映射规则(格式:{ 字段名: 显示名 },必填)
 * @param {String} [options.sheetName='数据表'] - 工作表名称
 * @param {String} [options.fileName='导出数据'] - 文件名(默认不包含时间戳)
 * @param {Boolean} [options.withTimestamp=true] - 是否在文件名后添加时间戳
 * @returns {Promise<void>}
 */
export const exportExcel = async (options) => {
    const {
        data,
        headerMap,
        sheetName = '数据表',
        fileName = '导出数据',
        withTimestamp = true
    } = options

    // 必填参数校验
    if (!data || !Array.isArray(data)) {
        ElMessage.error('导出失败:源数据必须为有效数组!')
        return
    }
    if (!headerMap || typeof headerMap !== 'object' || Object.keys(headerMap).length === 0) {
        ElMessage.error('导出失败:表头映射不可为空!')
        return
    }

    try {
        // 数据处理:根据 headerMap 提取并转换字段,同时处理空值与数字格式问题
        const exportData = data.map(item => {
            const row = {}
            Object.entries(headerMap).forEach(([key, label]) => {
                let value = item[key] ?? ''

                // 针对特定字段进行文本格式化(防止长数字被转为科学计数法)
                if (['phone', 'idCard', 'mobile', 'tel'].includes(key) && typeof value === 'number') {
                    value = `\t${value}` // 添加制表符以强制作为文本显示
                }
                row[label] = value
            })
            return row
        })

        // 构建工作表与工作簿
        const ws = XLSX.utils.json_to_sheet(exportData)
        const wb = XLSX.utils.book_new()
        XLSX.utils.book_append_sheet(wb, ws, sheetName)

        // 输出文件流并触发下载
        const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'array' })
        const blob = new Blob([wbout], {
            type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        })
        const url = URL.createObjectURL(blob)
    }
/**
 * 通用DOM表格导出功能(用于导出页面中当前显示的表格内容)
 * @param {Object} options 配置项
 * @param {String|HTMLElement} options.ele 表格的选择器或DOM元素(必填)
 * @param {String} [options.sheetName='当前页数据'] 工作表名称
 * @param {String} [options.fileName='当前页数据'] 导出文件名
 * @param {Boolean} [options.withTimestamp=true] 是否在文件名中添加时间戳
 * @returns {Promise<void>}
 */
export const exportTableDom = async (options) => {
  const {
    ele,
    sheetName = '当前页数据',
    fileName = '当前页数据',
    withTimestamp = true
  } = options

  // 获取目标表格元素
  let table = null
  if (typeof ele === 'string') {
    table = document.querySelector(ele)
  } else if (ele instanceof HTMLElement) {
    table = ele
  }

  // 若未找到对应DOM,则提示错误并终止操作
  if (!table) {
    ElMessage.error('导出失败:未找到表格DOM!')
    return
  }

  try {
    // 将DOM表格转换为工作表对象,保留原始格式
    const ws = XLSX.utils.table_to_sheet(table, { raw: true })
    const wb = XLSX.utils.book_new()
    XLSX.utils.book_append_sheet(wb, ws, sheetName)

    // 写入数据并生成二进制数组
    const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'array' })
    const blob = new Blob([wbout], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    })
    const url = URL.createObjectURL(blob)

    // 创建临时链接触发下载
    const a = document.createElement('a')
    const timestamp = withTimestamp ? `_${new Date().getTime()}` : ''
    a.download = `${fileName}${timestamp}.xlsx`
    a.href = url
    a.click()

    // 清理内存中的URL对象
    URL.revokeObjectURL(url)
    ElMessage.success(`《${fileName}》导出成功!`)
  } catch (error) {
    console.error('DOM表格导出失败:', error)
    ElMessage.error('导出失败,请重试!')
  }
}

/**
 * Excel数据导出核心方法
 * 将传入的数据和配置转化为Excel文件并触发浏览器下载
 * @param {Array<Object>} data 要导出的数据列表
 * @param {Array<Object>} columns 列配置,需包含prop和label字段
 * @param {String} [fileName='导出数据'] 文件名称
 * @param {String} [sheetName='数据表'] 工作表名称
 * @param {Boolean} [withTimestamp=true] 文件名是否附加时间戳
 */
export const exportExcel = async (data, columns, fileName = '导出数据', sheetName = '数据表', withTimestamp = true) => {
  try {
    // 构建表头映射:字段名 → 显示标题
    const headerMap = {}
    columns.forEach(col => {
      if (col.prop && col.label) {
        headerMap[col.prop] = col.label
      }
    })

    // 转换数据结构以匹配表头顺序
    const headerKeys = Object.keys(headerMap)
    const headerLabels = Object.values(headerMap)

    const exportData = [
      headerLabels, // 第一行为表头
      ...data.map(row => headerKeys.map(key => row[key] || ''))
    ]

    // 创建工作表与工作簿
    const ws = XLSX.utils.aoa_to_sheet(exportData)
    const wb = XLSX.utils.book_new()
    XLSX.utils.book_append_sheet(wb, ws, sheetName)

    // 输出字节流并生成可下载链接
    const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'array' })
    const blob = new Blob([wbout], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    })
    const url = URL.createObjectURL(blob)

    // 模拟点击进行文件下载
    const a = document.createElement('a')
    const timestamp = withTimestamp ? `_${new Date().getTime()}` : ''
    a.download = `${fileName}${timestamp}.xlsx`
    a.href = url
    a.click()

    // 释放资源
    URL.revokeObjectURL(url)
    ElMessage.success(`《${fileName}》导出成功!`)
  } catch (error) {
    console.error('Excel导出失败:', error)
    ElMessage.error('导出失败,请检查数据格式或重试!')
  }
}

/**
 * 自动解析 el-table 组件的列配置,生成字段与标签的映射关系
 * @param {Object} tableRef 对 el-table 的 ref 引用对象
 * @returns {Object} 返回格式为 { prop: label } 的表头映射对象
 */
export const getTableHeaderMap = (tableRef) => {
  if (!tableRef || !tableRef.columns) {
    ElMessage.warning('解析表头失败:表格ref无效!')
    return {}
  }

  const headerMap = {}

  // 遍历所有列,提取有效字段与标签
  tableRef.columns.forEach(col => {

if (col.prop && col.label && !col.hidden) { // 排除隐藏列

    headerMap[col.prop] = col.label

}

})

return headerMap

}

五、组件中使用示例

<template>
  <div class="excel-export-demo">
    <!-- 示例1:数组数据导出 -->
    <el-table
      ref="userTableRef"
      :data="userList"
      border
      style="width: 100%; margin-bottom: 20px"
    >
      <el-table-column prop="name" label="姓名" />
      <el-table-column prop="age" label="年龄" />
      <el-table-column prop="phone" label="手机号" />
      <el-table-column prop="email" label="邮箱" />
    </el-table>
    <el-button type="primary" @click="exportUserExcel">导出用户列表(手动headerMap)</el-button>
    <el-button type="primary" @click="exportUserExcelAuto">导出用户列表(自动解析表头)</el-button>

    <!-- 示例2:DOM表格导出(分页场景) -->
    <el-table
      :data="orderList"
      border
      id="order-table"
      style="width: 100%; margin-bottom: 20px"
    >
      <el-table-column prop="orderNo" label="订单号" />
      <el-table-column prop="amount" label="金额(元)" />
      <el-table-column prop="createTime" label="创建时间" />
    </el-table>
    <el-button type="primary" @click="exportOrderDom">导出当前订单页</el-button>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { exportExcel, exportTableDom, getTableHeaderMap } from '@/utils/exportExcel'

// 模拟用户数据
const userTableRef = ref(null)
const userList = ref([
  { name: '张三', age: 20, phone: 13800138000, email: 'zhangsan@test.com' },
  { name: '李四', age: 22, phone: 13900139000, email: 'lisi@test.com' },
  { name: '王五', age: 25, phone: 13700137000, email: 'wangwu@test.com' }
])

// 模拟订单数据(分页)
const orderList = ref([
  { orderNo: 'OD20251209001', amount: 199, createTime: '2025-12-09 10:00' },
  { orderNo: 'OD20251209002', amount: 299, createTime: '2025-12-09 11:00' }
])

// 1. 手动配置headerMap导出
const exportUserExcel = () => {
  exportExcel({
    data: userList.value,
    headerMap: {
      name: '姓名',
      age: '年龄',
      phone: '手机号' // 仅导出这3个字段
    },
    fileName: '用户列表',
    sheetName: '2025用户数据',
    withTimestamp: true
  })
}

// 2. 自动解析表头导出
const exportUserExcelAuto = () => {
  const headerMap = getTableHeaderMap(userTableRef.value)
  exportExcel({
    data: userList.value,
    headerMap, // 自动解析所有列的prop和label
    fileName: '用户列表_自动解析',
    sheetName: '用户数据'
  })
}

// 3. 导出DOM表格(当前页)
const exportOrderDom = () => {
  exportTableDom({
    ele: '#order-table',
    fileName: '12月订单列表',
    sheetName: '2025-12-09订单'
  })
}
</script>

六、常见问题与解决方案

  • 问题现象:手机号/身份证显示为科学计数法
    原因分析:数字过长导致Excel自动进行格式化处理
    解决方案:工具已内置相应处理机制,可通过为指定字段添加配置项以强制设置为文本格式;也可在数据层将对应字段值手动转换为字符串类型
    \t
  • 问题现象:导出后的Excel文件内容为空
    原因分析:原始数据为空或headerMap的字段映射配置有误
    解决方案:确认源数据为非空数组;检查
    data
    中的字段名称是否与实际数据结构完全匹配
    headerMap
  • 问题现象:DOM导出时无法找到目标表格
    原因分析:可能是选择器书写错误,或目标DOM尚未完成挂载
    解决方案:确保使用的选择器正确无误;或通过传入实际的DOM元素对象来避免选择器问题
    ref
    (可参考
    tableRef.value.$el
    的方式)
  • 问题现象:导出文件出现乱码
    原因分析:Blob的数据类型配置不正确
    解决方案:工具已在底层默认配置了正确的MIME类型,确保输出编码正常
    Blob
    (具体类型见
    application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
  • 问题现象:合并单元格在导出后显示异常
    原因分析:xlsx库对从DOM直接解析的合并单元格支持能力有限
    解决方案:建议优先采用「数组数据导出」模式,减少对DOM结构的依赖,提升兼容性

七、扩展说明

  • 支持自定义格式:可在
    exportExcel
    方法内的
    exportData
    处理阶段,增加对日期、金额等特殊字段的格式化逻辑,实现灵活输出。
  • 大文件导出优化:当导出数据量超过一万条时,建议使用
    XLSX.writeFile
    替代传统的
    Blob
    下载方式,有效防止浏览器内存溢出问题。
  • 多工作表导出功能:可通过扩展
    exportExcel
    方法,支持接收多个数据集
    data + headerMap
    ,从而生成包含多个工作表的Excel文件,满足复杂报表需求。
  • 样式定制能力:当前所用的
    xlsx
    库基础版本不支持Excel样式设置。如需实现字体、边框、背景色等样式控制,可考虑升级至
    xlsx-style
    exceljs
    等更高级的库。
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:Element EXCEL xcel PLUS exce

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
扫码
拉您进交流群
GMT+8, 2026-2-2 10:51