news 2026/10/14 11:54:21

使用SheetJS Pro实现前端Excel导出与样式设置

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用SheetJS Pro实现前端Excel导出与样式设置

1. 项目背景与核心需求

最近在重构一个后台管理系统时,遇到了一个典型的需求:前端需要将表格数据导出为Excel文件,并且要求保留样式(如单元格颜色、字体加粗、边框等)。这个功能在数据报表、统计分析和数据交接等场景中非常常见。经过技术调研,最终选择了SheetJS的Pro版本(即sheetjs-style.js)来实现这个需求。

为什么选择SheetJS而不是其他库?主要原因有三点:

  1. 社区活跃度高,维护良好,长期来看更可靠
  2. 功能全面,支持xlsx、xls等多种格式
  3. Pro版本支持样式设置,能满足我们的设计需求

2. 环境准备与基础配置

2.1 安装依赖

首先需要在Vue项目中安装SheetJS的核心库和Pro版本:

npm install xlsx npm install xlsx-style

这里有个坑需要注意:官方仓库的xlsx-style已经不再维护,我们需要使用社区维护的fork版本。在package.json中应该这样指定:

"dependencies": { "xlsx": "^0.18.5", "xlsx-style": "git+https://github.com/protobi/js-xlsx.git" }

2.2 全局引入配置

为了在整个项目中方便使用,我们在main.js中全局引入并挂载到Vue原型上:

import XLSX from 'xlsx' import XLSXStyle from 'xlsx-style' Vue.prototype.$xlsx = XLSX Vue.prototype.$xlsxStyle = XLSXStyle

3. 核心实现逻辑详解

3.1 数据结构准备

假设我们有一个用户数据表格需要导出,数据结构如下:

const userData = [ { id: 1, name: '张三', age: 28, department: '研发部', status: '在职' }, { id: 2, name: '李四', age: 32, department: '市场部', status: '离职' }, // 更多数据... ]

3.2 创建工作簿和工作表

// 创建工作簿 const wb = this.$xlsx.utils.book_new() // 将JSON数据转换为工作表 const ws = this.$xlsx.utils.json_to_sheet(userData) // 设置表头样式 ws['A1'].s = { font: { bold: true, color: { rgb: "FFFFFF" } }, fill: { fgColor: { rgb: "4472C4" } }, alignment: { horizontal: "center" } } // 将工作表添加到工作簿 this.$xlsx.utils.book_append_sheet(wb, ws, "用户数据")

3.3 样式设置详解

SheetJS的样式设置是通过单元格的s属性实现的,支持以下常用样式:

{ font: { // 字体样式 name: 'Arial', sz: 12, bold: true, italic: false, underline: true, color: { rgb: "FF0000" } // 红色 }, fill: { // 填充样式 fgColor: { rgb: "FFFF00" }, // 黄色背景 patternType: "solid" }, border: { // 边框样式 top: { style: "thin", color: { rgb: "000000" } }, bottom: { style: "thin", color: { rgb: "000000" } }, left: { style: "thin", color: { rgb: "000000" } }, right: { style: "thin", color: { rgb: "000000" } } }, alignment: { // 对齐方式 horizontal: "center", vertical: "center", wrapText: true }, numFmt: "0.00%" // 数字格式 }

4. 完整导出功能实现

4.1 导出函数封装

下面是一个完整的导出函数实现:

exportExcel() { // 1. 准备数据 const data = this.getTableData() // 获取表格数据 // 2. 创建工作簿 const wb = this.$xlsx.utils.book_new() // 3. 转换数据为工作表 const ws = this.$xlsx.utils.json_to_sheet(data) // 4. 设置表头样式 const headerStyle = { font: { bold: true, color: { rgb: "FFFFFF" } }, fill: { fgColor: { rgb: "4472C4" } }, alignment: { horizontal: "center" } } // 获取表头范围 (假设有5列) for(let i = 0; i < 5; i++) { const cell = this.$xlsx.utils.encode_cell({ c: i, r: 0 }) ws[cell].s = headerStyle } // 5. 设置数据行样式 Object.keys(ws).forEach(key => { if(key !== '!ref' && key !== '!cols' && key !== '!rows') { if(!ws[key].s) ws[key].s = {} ws[key].s.alignment = { vertical: "center" } } }) // 6. 设置列宽 ws['!cols'] = [ { width: 10 }, // 第一列 { width: 20 }, // 第二列 { width: 15 }, // 第三列 { width: 25 }, // 第四列 { width: 15 } // 第五列 ] // 7. 添加到工作簿并导出 this.$xlsx.utils.book_append_sheet(wb, ws, "Sheet1") this.$xlsxStyle.writeFile(wb, "用户数据.xlsx") }

4.2 性能优化技巧

当数据量较大时(超过1000行),导出可能会变慢。可以采用以下优化方案:

  1. 分块处理:将大数据集分成多个小块处理
  2. 简化样式:只对必要的单元格应用复杂样式
  3. 使用Web Worker:将导出操作放到后台线程
// Web Worker示例 const worker = new Worker('./excelExport.worker.js') worker.postMessage({ data: largeDataSet, fileName: '大数据导出.xlsx' }) worker.onmessage = (e) => { if(e.data.success) { this.$message.success('导出成功') } else { this.$message.error('导出失败') } }

5. 常见问题与解决方案

5.1 样式不生效问题

问题现象:设置了样式但导出的Excel文件没有显示样式。

排查步骤:

  1. 确认使用的是xlsx-style而不是xlsx
  2. 检查样式对象格式是否正确
  3. 确保单元格引用正确(如A1、B2等)

解决方案:

// 错误示例 ws['A1'].style = { font: { bold: true } } // 错误属性名 // 正确示例 ws['A1'].s = { font: { bold: true } } // 正确属性名

5.2 中文乱码问题

问题现象:导出的Excel文件中中文显示为乱码。

解决方案:

  1. 确保HTML页面使用UTF-8编码
  2. 在Blob对象中指定编码:
const blob = new Blob( [this.$xlsxStyle.write(wb, { bookType: 'xlsx', type: 'binary' })], { type: 'application/octet-stream;charset=utf-8' } )

5.3 大文件导出崩溃

问题现象:当数据量很大时,浏览器可能会卡死或崩溃。

优化方案:

  1. 使用分页加载数据
  2. 采用流式导出
  3. 显示导出进度
// 分页导出示例 async function exportLargeData(data, chunkSize = 1000) { const wb = this.$xlsx.utils.book_new() let page = 1 for(let i = 0; i < data.length; i += chunkSize) { const chunk = data.slice(i, i + chunkSize) const ws = this.$xlsx.utils.json_to_sheet(chunk) this.$xlsx.utils.book_append_sheet(wb, ws, `Page ${page++}`) // 更新进度 this.exportProgress = Math.min(100, Math.round(i / data.length * 100)) await new Promise(resolve => setTimeout(resolve, 0)) } this.$xlsxStyle.writeFile(wb, '大数据导出.xlsx') }

6. 高级功能实现

6.1 合并单元格

实现类似"跨列居中"的效果:

// 合并A1到E1单元格 ws['!merges'] = [ { s: { r: 0, c: 0 }, e: { r: 0, c: 4 } } ] // 设置合并后单元格的样式 ws['A1'].s = { font: { bold: true, sz: 16 }, alignment: { horizontal: "center" } }

6.2 条件格式

虽然SheetJS不支持直接设置Excel的条件格式,但我们可以通过编程方式实现类似效果:

data.forEach((item, rowIndex) => { Object.keys(item).forEach((key, colIndex) => { const cellRef = this.$xlsx.utils.encode_cell({ r: rowIndex + 1, // +1因为第一行是表头 c: colIndex }) // 根据状态设置不同颜色 if(key === 'status') { ws[cellRef].s = { fill: { fgColor: { rgb: item.status === '在职' ? 'C6EFCE' : 'FFC7CE' } }, font: { color: { rgb: item.status === '在职' ? '006100' : '9C0006' } } } } }) })

6.3 多Sheet导出

一个Excel文件可以包含多个工作表:

// 第一个工作表 const ws1 = this.$xlsx.utils.json_to_sheet(data1) this.$xlsx.utils.book_append_sheet(wb, ws1, "用户数据") // 第二个工作表 const ws2 = this.$xlsx.utils.json_to_sheet(data2) this.$xlsx.utils.book_append_sheet(wb, ws2, "部门统计") // 第三个工作表(空表带样式) const ws3 = this.$xlsx.utils.aoa_to_sheet([]) ws3['A1'] = { v: "统计报表", t: 's', s: headerStyle } this.$xlsx.utils.book_append_sheet(wb, ws3, "报表")

7. 实际项目中的经验总结

在多个项目中实现Excel导出功能后,我总结了以下几点经验:

  1. 样式统一管理:将常用的样式提取为常量,便于维护
// styles.js export const HEADER_STYLE = { font: { bold: true, color: { rgb: "FFFFFF" }, sz: 12 }, fill: { fgColor: { rgb: "4472C4" } }, alignment: { horizontal: "center", vertical: "center" } } export const WARNING_STYLE = { font: { color: { rgb: "9C0006" } }, fill: { fgColor: { rgb: "FFC7CE" } } }
  1. 性能监控:添加导出性能日志
console.time('Excel导出') // ...导出操作 console.timeEnd('Excel导出') // 打印耗时
  1. 用户反馈:对于大数据量导出,提供进度提示
<template> <div v-if="exporting"> <progress :value="exportProgress" max="100"></progress> <span>{{ exportProgress }}%</span> </div> </template>
  1. 错误边界:捕获并处理可能的错误
try { this.$xlsxStyle.writeFile(wb, fileName) } catch (error) { console.error('导出失败:', error) this.$message.error(`导出失败: ${error.message}`) // 回退到无样式导出 try { this.$xlsx.writeFile(wb, fileName) this.$message.warning('已导出无样式版本') } catch (fallbackError) { console.error('回退导出失败:', fallbackError) } }
  1. 浏览器兼容性:针对不同浏览器做适配处理
// IE11兼容方案 if (window.Blob && window.navigator.msSaveOrOpenBlob) { const blob = new Blob( [this.$xlsxStyle.write(wb, { bookType: 'xlsx', type: 'binary' })], { type: 'application/octet-stream' } ) window.navigator.msSaveOrOpenBlob(blob, fileName) } else { this.$xlsxStyle.writeFile(wb, fileName) }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 11:53:26

高端礼盒包装制作10步流程与质感提升技巧

1. 项目概述&#xff1a;高端礼盒包装的制作价值与市场需求礼盒包装作为产品附加值的重要载体&#xff0c;在奢侈品、数码产品、食品保健品等领域有着不可替代的作用。一个制作精良的天地盖礼盒&#xff0c;能让普通商品的价值感提升30%以上。我从事包装设计行业12年&#xff0…

作者头像 李华
网站建设 2026/10/14 11:53:26

零基础学编程第一门语言怎么选?Python依然是首选

前两天又有朋友来问我&#xff0c;孩子想学编程&#xff0c;第一门语言选什么。我说Python。他愣了一下说&#xff0c;这也太“老生常谈”了吧&#xff0c;现在不是很多人推荐学别的吗&#xff1f;我说你听我讲完理由再说。 我做技术这十几年&#xff0c;前后带过不少编程零基…

作者头像 李华
网站建设 2026/10/14 11:53:16

局域网自建AI Agent平台:Docker部署本地大模型与编排服务实战

1. 为什么要在局域网里自建 AI Agent 平台1.1 从"调用云端 API"到"把模型搬进机房"的转变过去一年&#xff0c;我身边不少做企业内部工具的朋友都经历了同一个心路历程&#xff1a;一开始图省事&#xff0c;直接调用公有云的大模型接口&#xff0c;写几行代…

作者头像 李华
网站建设 2026/10/14 11:52:07

840D sl 数控系统 ToolBox 4.8.07 安装调试与项目集成指南

简介&#xff1a;西门子840DSL高端数控系统配套的STEP7工具箱&#xff08;ToolBox 4.8.07&#xff09;&#xff0c;面向机械加工、自动化领域从事PLC编程与运动控制的技术人员&#xff0c;适用于加工中心、铣床、车床等精密设备的控制程序设计。工具包内置STEP7编程环境&#x…

作者头像 李华
网站建设 2026/10/14 11:51:22

Zemax MTF优化评价函数模板实践指南

1. 项目背景与核心价值在光学设计领域&#xff0c;调制传递函数&#xff08;MTF&#xff09;是评价成像系统性能的黄金标准。作为一名光学工程师&#xff0c;我经常需要花费大量时间反复调整评价函数来优化MTF性能。经过多年实践&#xff0c;我总结出了一套高效的Zemax MTF优化…

作者头像 李华
网站建设 2026/10/14 11:50:40

仿京东商品详情页开发实战:从数据结构到SKU联动的避坑指南

简介&#xff1a;一份仿京东商品展示详情页的前端实战项目&#xff0c;适合正在学习电商页面开发的前端初学者与进阶开发者&#xff0c;也可作为商城项目的页面参考。项目基于 HTML、CSS 和 JavaScript 实现&#xff0c;涵盖商品主图轮播、价格与库存展示、规格选择切换、用户评…

作者头像 李华