尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

纯前端通过xlsx.js导出Excel表格:完整示例与实战指南

纯前端通过xlsx.js导出Excel表格:完整示例与实战指南 1. 前言为什么选择纯前端导出Excel在Web应用中导出Excel表格是常见的需求。传统方案依赖后端生成文件并返回但存在以下痛点服务器压力大每次导出都需要后端处理消耗服务器资源。响应延迟数据需要往返服务器用户体验不佳。依赖网络网络不稳定时导出可能失败。纯前端导出方案如使用xlsx.js完美解决了这些问题完全在浏览器中完成数据生成、格式处理、文件下载均在客户端进行。零服务器依赖减轻后端负担提升系统扩展性。即时响应用户点击后立即下载体验流畅。本文将详细介绍如何使用xlsx.js实现功能丰富的Excel导出涵盖基础导出、合并单元格、样式设置及其他常用高级功能。2. 环境准备与xlsx.js引入2.1 安装xlsx.js有多种方式引入xlsx.js库xlsx基础库不提供样式设置可以使用xlsx-js-style库这个库是xlsx库的fork版本并添加了样式定义详细样式可以查看https://github.com/gitbrent/xlsx-js-style/方式一CDN引入推荐初学者!-- 在HTML文件中引入 -- script srchttps://unpkg.com/xlsx/dist/xlsx.full.min.js/script方式二NPM安装适用于现代前端项目# 在项目目录中执行 npm install xlsx # 或使用yarn yarn add xlsx// 在JavaScript/TypeScript文件中导入 import * as XLSX from xlsx; // 或按需导入 import { utils, writeFile } from xlsx;2.2 基础HTML结构!DOCTYPE html html langzh-CN head meta charsetUTF-8 title前端Excel导出示例/title script srchttps://unpkg.com/xlsx/dist/xlsx.full.min.js/script /head body button idexportBtn导出Excel/button script srcapp.js/script /body /html3. 基础导出从数据到Excel文件3.1 最简单的二维数组导出// 示例数据二维数组 const data [ [姓名, 年龄, 城市, 入职日期], [张三, 28, 北京, 2023-01-15], [李四, 32, 上海, 2022-08-22], [王五, 25, 广州, 2024-03-10] ]; function exportSimpleExcel() { // 1. 创建工作簿 const wb XLSX.utils.book_new(); // 2. 创建工作表 const ws XLSX.utils.aoa_to_sheet(data); // 3. 将工作表添加到工作簿 XLSX.utils.book_append_sheet(wb, ws, 员工信息); // 4. 生成Excel文件并下载 XLSX.writeFile(wb, 员工信息表.xlsx); } // 绑定按钮点击事件 document.getElementById(exportBtn).addEventListener(click, exportSimpleExcel);3.2 从JSON对象数组导出更常用const employees [ { id: 1, name: 张三, department: 技术部, salary: 15000, joinDate: 2023-01-15 }, { id: 2, name: 李四, department: 市场部, salary: 12000, joinDate: 2022-08-22 }, { id: 3, name: 王五, department: 人事部, salary: 10000, joinDate: 2024-03-10 } ]; function exportJsonExcel() { // 1. 将JSON数组转换为工作表 const ws XLSX.utils.json_to_sheet(employees); // 2. 创建工作簿并添加工作表 const wb XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, 员工数据); // 3. 导出文件 XLSX.writeFile(wb, 员工数据表.xlsx); }3.3 设置表头自定义列顺序和标题function exportWithCustomHeaders() { // 定义表头映射对象属性 - 显示标题 const headerMap [ { key: name, title: 姓名 }, { key: department, title: 部门 }, { key: salary, title: 薪资(元) }, { key: joinDate, title: 入职日期 }, ]; // 1. 提取表头标题 const headers headerMap.map((item) item.title); // 2. 提取数据行按映射顺序 const rows employees.map((emp) headerMap.map((item) emp[item.key])); // 3. 合并表头和数据 const sheetData [headers, ...rows]; // 4. 创建并导出 const ws XLSX.utils.aoa_to_sheet(sheetData); const wb XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, 自定义表头); XLSX.writeFile(wb, 自定义表头.xlsx); }4. 合并单元格实战示例4.1 基础合并合并表头区域function exportWithMergedHeader() { const data [ [员工信息统计表], // 第一行标题 [], // 第二行空行用于样式 [姓名, 年龄, 部门, 薪资], ]; const ws XLSX.utils.aoa_to_sheet(data); // 关键设置合并单元格 // 语法ws[!merges] [{ s: {r: 开始行, c: 开始列}, e: {r: 结束行, c: 结束列} }] ws[!merges] [ // 合并第一行的A-D列作为标题 { s: { r: 0, c: 0 }, e: { r: 0, c: 3 } }, // 合并第二行的A-D列作为空行用于样式间隔 { s: { r: 1, c: 0 }, e: { r: 1, c: 3 } }, ]; const wb XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, 合并表头示例); XLSX.writeFile(wb, 合并表头.xlsx); }4.2 复杂合并分组数据合并function exportGroupedData() { // 模拟分组数据按部门分组 const data [ [部门, 姓名, 职位, 工龄], [技术部, 张三, 前端工程师, 3], [, 李四, 后端工程师, 5], // 部门列留空准备合并 [, 王五, 测试工程师, 2], [市场部, 赵六, 市场专员, 4], [, 钱七, 销售经理, 6], [人事部, 孙八, HR专员, 2], ]; const ws XLSX.utils.aoa_to_sheet(data); // 设置合并将相同部门的单元格合并 ws[!merges] [ // 技术部A2-A4行索引从0开始 { s: { r: 1, c: 0 }, e: { r: 3, c: 0 } }, // 市场部A5-A6 { s: { r: 4, c: 0 }, e: { r: 5, c: 0 } }, // 人事部A7单独一行不需要合并 ]; const wb XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, 分组合并示例); XLSX.writeFile(wb, 分组合并.xlsx); }4.3 动态合并根据数据自动合并function exportDynamicMerged() { const salesData [ [月份, 产品, 销售额, 增长率], [一月, 产品A, 150000, 15%], [, 产品B, 120000, 8%], [, 产品C, 180000, 22%], [二月, 产品A, 165000, 10%], [, 产品B, 130000, 8%], [, 产品C, 200000, 11%], [三月, 产品A, 180000, 9%], [, 产品B, 140000, 8%], [, 产品C, 220000, 10%], ]; const ws XLSX.utils.aoa_to_sheet(salesData); const merges []; let startRow 1; // 数据从第2行开始索引1 // 动态计算合并区域 for (let i 1; i salesData.length; i) { if (salesData[i][0] ! ) { // 月份不为空是新月份的开始 if (i startRow) { // 合并上一个月份的月份列 merges.push({ s: { r: startRow, c: 0 }, e: { r: i - 1, c: 0 } }); } startRow i; } } // 合并最后一个月份 if (startRow salesData.length - 1) { merges.push({ s: { r: startRow, c: 0 }, e: { r: salesData.length - 1, c: 0 }, }); } ws[!merges] merges; const wb XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, 动态合并示例); XLSX.writeFile(wb, 动态合并.xlsx); }5. 单元格样式设置详解5.1 基础样式字体、颜色、对齐function exportWithBasicStyles() { const data [ [样式演示表], [项目, 数值, 状态], [收入, 50000, 良好], [支出, 30000, 正常], [利润, 20000, 优秀], ]; const ws XLSX.utils.aoa_to_sheet(data); // 设置单元格样式 // 单元格地址A1, B2, C3 等 const cellStyles { // 标题样式A1单元格 A1: { s: { font: { bold: true, sz: 16, color: { rgb: FF0000 } }, // 红色加粗16号字 alignment: { horizontal: center, vertical: center }, fill: { fgColor: { rgb: FFFF00 } }, // 黄色背景 }, }, // 表头样式A2:C2 A2: { s: { font: { bold: true }, alignment: { horizontal: center } } }, B2: { s: { font: { bold: true }, alignment: { horizontal: center } } }, C2: { s: { font: { bold: true }, alignment: { horizontal: center } } }, // 数值列右对齐 B3: { s: { alignment: { horizontal: right } } }, B4: { s: { alignment: { horizontal: right } } }, B5: { s: { alignment: { horizontal: right } } }, // 状态列根据值设置颜色 C3: { s: { font: { color: { rgb: 008000 } } } }, // 绿色 C4: { s: { font: { color: { rgb: 0000FF } } } }, // 蓝色 C5: { s: { font: { color: { rgb: FFA500 } } } }, // 橙色 }; // 应用样式到工作表 Object.keys(cellStyles).forEach((cell) { if (!ws[cell]) ws[cell] { v: }; ws[cell] { ...ws[cell], ...cellStyles[cell] }; }); // 设置列宽 ws[!cols] [ { wpx: 100 }, // A列宽度100像素 { wpx: 80 }, // B列宽度80像素 { wpx: 100 }, // C列宽度100像素 ]; const wb XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, 基础样式); XLSX.writeFile(wb, 基础样式.xlsx); }5.2 条件格式根据数值设置样式function exportWithConditionalFormatting() { const scores [ [学生, 语文, 数学, 英语, 总分], [张三, 85, 92, 78, 255], [李四, 62, 75, 80, 217], [王五, 95, 88, 92, 275], [赵六, 70, 65, 72, 207], ]; const ws XLSX.utils.aoa_to_sheet(scores); // 遍历数据行跳过表头 for (let r 1; r scores.length; r) { const total scores[r][4]; // 总分在E列索引4 // 根据总分设置行样式 let rowStyle {}; if (total 250) { rowStyle { fill: { fgColor: { rgb: C6EFCE } }, // 浅绿色背景 font: { bold: true, color: { rgb: 006100 } }, }; } else if (total 220) { rowStyle { fill: { fgColor: { rgb: FFC7CE } }, // 浅红色背景 font: { color: { rgb: 9C0006 } }, }; } // 应用样式到整行 if (Object.keys(rowStyle).length 0) { [A, B, C, D, E].forEach((col, cIndex) { const cellAddr col (r 1); // Excel行号从1开始 if (!ws[cellAddr]) ws[cellAddr] { v: scores[r][cIndex] }; ws[cellAddr].s rowStyle; }); } } const wb XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, 条件格式); XLSX.writeFile(wb, 条件格式.xlsx); }5.3 数字格式货币、百分比、日期function exportWithNumberFormat() { const financialData [ [项目, 金额, 增长率, 日期], [收入, 1500000, 0.15, new Date(2024-01-15)], [成本, 800000, 0.08, new Date(2024-01-15)], [利润, 700000, 0.25, new Date(2024-01-15)] ]; const ws XLSX.utils.aoa_to_sheet(financialData); // 设置数字格式 const formats { // B列货币格式人民币千位分隔符两位小数 B2: { s: { numFmt: ¥#,##0.00 } }, B3: { s: { numFmt: ¥#,##0.00 } }, B4: { s: { numFmt: ¥#,##0.00 } }, // C列百分比最终版整理了工具import * as XLSX from xlsx-js-style export function exportExcel(excelName, data, columns) { const newData [] const keys columns.map((item) item[prop]) const headers columns.map((item) item[label]) data.forEach((item) { const row [] for (let key of keys) { row.push(item[key]) } newData.push(row) }) // 添加表头 newData.unshift(headers) const workbook XLSX.utils.book_new() const worksheet XLSX.utils.json_to_sheet(newData, { skipHeader: true, }) // 设置列宽 const columnsWidth columns.map((item) { return { wpx: item.width, } }) worksheet[!cols] columnsWidth // 设置表头样式 columns.forEach((item, index) { if (item[excelStyle]) { const cell indexToLetters(index) 1 worksheet[cell].s item[excelStyle] } }) XLSX.utils.book_append_sheet(workbook, worksheet, Sheet1) XLSX.writeFile(workbook, ${excelName}.xlsx) } function indexToLetters(i) { if (i 0 i 25) { return String.fromCharCode(65 i) } else { return undefined } }单元格样式示例// STEP 1: Create a new workbook const wb XLSX.utils.book_new(); // STEP 2: Create data rows and styles let row [ { v: Courier: 24, t: s, s: { font: { name: Courier, sz: 24 } } }, { v: bold color, t: s, s: { font: { bold: true, color: { rgb: FF0000 } } } }, { v: fill: color, t: s, s: { fill: { fgColor: { rgb: E9E9E9 } } } }, { v: line\nbreak, t: s, s: { alignment: { wrapText: true } } }, ]; // STEP 3: Create worksheet with rows; Add worksheet to workbook const ws XLSX.utils.aoa_to_sheet([row]); XLSX.utils.book_append_sheet(wb, ws, readme demo); // STEP 4: Write Excel file to browser XLSX.writeFile(wb, xlsx-js-style-demo.xlsx);单元格样式属性单元格样式由一个大致与 OpenXML 结构对应的样式对象指定。当前支持的样式属性包括alignment对齐方式、border边框、fill填充、font字体、numFmt数字格式。样式属性子属性默认值描述/取值alignmentverticalbottomtop顶部对齐或center居中对齐或bottom底部对齐horizontalleftleft左对齐或center居中对齐或right右对齐wrapTextfalsetrue自动换行或false不自动换行textRotation00到180之间的数值或255//180表示向下旋转 180 度255为特殊值表示垂直对齐bordertop{ style: BORDER_STYLE, color: COLOR_STYLE }上边框样式和颜色bottom{ style: BORDER_STYLE, color: COLOR_STYLE }下边框样式和颜色left{ style: BORDER_STYLE, color: COLOR_STYLE }左边框样式和颜色right{ style: BORDER_STYLE, color: COLOR_STYLE }右边框样式和颜色diagonal{ style: BORDER_STYLE, color: COLOR_STYLE, diagonalUp: true/false, diagonalDown: true/false }对角线样式、颜色及方向fillpatternTypenonesolid纯色填充或none无填充fgColor前景色参见COLOR_STYLEbgColor背景色参见COLOR_STYLEfontboldfalse字体加粗true是或false否color字体颜色COLOR_STYLEitalicfalse字体斜体true是或false否nameCalibri字体名称strikefalse字体删除线true是或false否sz11字体大小磅underlinefalse字体下划线true是或false否vertAlignsuperscript上标或subscript下标numFmt0示例0// 内置格式的整数索引参见 StyleBuilder.SSF 属性示例0.00%// 匹配内置格式的字符串参见 StyleBuilder.SSF示例0.0%// 指定自定义格式的字符串示例0.00%;\\(0.00%\\);\\-;// 指定自定义格式的字符串其中特殊字符需转义示例m/dd/yy// 使用 Excel 格式表示法的日期格式字符串COLOR_STYLE{对象} 属性border、fill、font的颜色通过一个名称/值对象来指定可使用以下方式之一颜色属性描述示例rgb十六进制 RGB 值{rgb: FFCC00}theme主题颜色索引{theme: 4}// (0-n) // 主题颜色索引 4蓝色强调色 1tint色调百分比{theme: 1, tint: 0.4}// (蓝色强调色 1浅 40%)BORDER_STYLE{字符串} 属性边框样式属性为以下值之一dashDotDotdashDotdasheddottedhairmediumDashDotDotmediumDashDotmediumDashedmediumslantDashDotthickthin边框说明合并区域的边框需为合并区域内的每个单元格单独指定。例如要为一个 3x3 单元格的合并区域应用方框边框需要为八个不同的单元格指定边框样式左边框左侧三个单元格右边框右侧单元格上边框顶部单元格下边框底部单元格
返回列表