当前位置: 首页 > java >正文

vue3 解析excel字节流文件 以表格形式显示页面上 带公式

导出:解析excel 二进制文件

https://blog.csdn.net/weixin_43746297/article/details/146204040

导入:解析excel 二进制文件

解析:

注意:使用前需通过npm install xlsx安装依赖库

动态表头生成

使用 sheet_to_json 的 header:1 参数提取首行作为表头

Excel工作表转换为JSON格式:

const jsonData = XLSX.utils.sheet_to_json(firstSheet, {header: 1,raw: false, //保留公式defval: ""
})
参数配置如下:
  • header:  指定输出结果为二维数组格式,每行数据以数组形式呈现。若不设置该参数或设为其他值,则默认输出键值对格式的对象数组。

  • raw: false 保留单元格原始公式而非计算结果,适用于需要获取Excel公式的场景。若设为true则输出公式计算结果。

  • defval: "" 为空单元格设置默认值为空字符串,避免解析时跳过空值导致字段缺失。未设置时默认会忽略空单元格。

jsonData结构取决于header参数:
  • header:1时:结果为Array<Array<any>>,每行数据为子数组
  • 默认情况:结果为Array<Object>,首行作为键名
典型应用场景包括:
  • 前端导入带公式的Excel表格
  • 需要严格保留空单元格位置的表格处理
  • 复杂表头数据的结构化转换

使用xlsx库读取Excel数据

const workbook = XLSX.read(data, {type: 'array',cellFormula: true,cellHTML: false});
主要功能如下:
  • type: 'array'参数表示输入数据是Uint8Array类型的二进制数组
  • cellFormula: true会保留Excel单元格中的公式信息,而不是只获取计算结果
  • cellHTML: false表示不需要将单元格内容转换为HTML格式
workbook对象包含属性:
  • SheetNames属性(工作表名称列表)
  • Sheets对象(包含各个工作表数据)
典型使用场景包括:
  • 前端导入带公式的Excel文件
  • 需要保留原始公式而非计算结果的场景

从接口中获取

1.封装接口方法 获取excel字节流:

封装示例

封装方法,调用方法和传参形式依照自己的,这里只是示例

注意:responseType: 'arraybuffer'   必填***

 调用方法
  exportHandover({'传参':'传参'}).then((res) => {// 获取到二进制流  res}).catch((err) => {//弹出错误信息});
  •  这里是解析二进制流之后的数据格式 可自定义,可查看 下方完整代码
        arr.push({sheetName,columns: headers.map((h, i) => ({prop: `col${i}`,label: h})),list: [{columns: headers.map((h, i) => ({prop: `col${i}`,label: h})),data: dataRows.map(row => {return headers.reduce((obj, header, idx) => {obj[`col${idx}`] = row[idx] || ""return obj}, {})})}]})
完整代码 :

此段代码适用于 excel 单文件/多文件

<template><div class="layout-padding w100"><div class="layout-padding-auto layout-padding-view"><el-tabs style="height: calc(100% - 50px)" v-model="activeFile" type="card"><el-tab-panev-for="file in fileData":key="file.sheetName":label="file.sheetName":name="file.sheetName"class="table-container"><el-table:data="file.list"border:header-cell-style="{ borderColor: '#C0C0C0',textAlign:'center' }":cell-style="{ borderColor: '#C0C0C0',textAlign:'center '}"><el-table-columnv-for="col in file.columns":key="col.prop":prop="col.prop":label="col.label"/></el-table></el-tab-pane></el-tabs></div></div>
</template><script setup lang="ts" name="team">
import {useI18n} from 'vue-i18n';
import {reactive, ref, onMounted} from 'vue';
import {viewDeta} from '/@/stores/viewDeta';
import {exportHandover} from "/@/api/shiftHandover";
import {downBlobFile} from '/@/utils/other';
import {ElLoading} from 'element-plus';
import * as XLSX from 'xlsx';
import {useMessage} from "/@/hooks/message";const stores = viewDeta();
// 引入组件
const {t} = useI18n();
// 定义变量内容
const editFormDialog = ref();
const fileData = ref()
const activeFile = ref()
const queryForm = reactive({yearMonth: new Date().toISOString().slice(0, 7),deptId: '',roleId: '',
})
const getDeptData = () => {if (stores.$state.rolesName != undefined) {const loading = ElLoading.service({lock: true,text: '数据加载中...',background: 'rgba(5,5,5,0.6)',})exportHandover({参数}).then((res) => {const data = new Uint8Array(res)loading.close()const workbook = XLSX.read(data, {type: 'array',cellFormula: true,cellHTML: false});let arr = []workbook.SheetNames.forEach((sheetName) => {const firstSheet = workbook.Sheets[sheetName]const jsonData = XLSX.utils.sheet_to_json(firstSheet, {header: 1,raw: false,defval: ""})const headers = jsonData[0] || []const dataRows = jsonData.slice(1)arr.push({sheetName,columns: headers.map((h, i) => ({prop: `col${i}`,label: h})),list: [{columns: headers.map((h, i) => ({prop: `col${i}`,label: h})),data: dataRows.map(row => {return headers.reduce((obj, header, idx) => {obj[`col${idx}`] = row[idx] || ""return obj}, {})})}]})})arr.map((item) => {item.list = item.list.flatMap(r => r.data)})fileData.value = arractiveFile.value = fileData.value[0].sheetName}).catch((err) => {useMessage().error(err.msg);loading.close()});}
};onMounted(() => {
});
</script>
<style scoped lang="scss">
.table-container {display: flex;flex-direction: column;height: 100%; /* 或父容器高度 */
}.table-container > .el-table {flex: 1;min-height: 0; /* 关键属性 */
}
</style>
结果:

2.ajax方法直接获取

接口路径:/api/excel

使用axios时需设置 responseType: 'arraybuffer' 'blob'接收二进制流

 const res = await axios.get('/api/excel', {responseType: 'arraybuffer'
});
完整代码:

此代码适用于单文件,如需多文件 参考上方封装接口方法

<template><div><button @click="loadExcelData">加载Excel数据</button><table v-if="tableData.length"><thead><tr><th v-for="col in columns" :key="col.key">{{ col.title }}</th></tr></thead><tbody><tr v-for="(row, rowIndex) in tableData" :key="rowIndex"><td v-for="col in columns" :key="col.key">{{ row[col.key] }}</td></tr></tbody></table></div>
</template><script setup>
import { ref } from 'vue';
import axios from 'axios';
import * as XLSX from 'xlsx';// 表格数据和列配置
const tableData = ref([]);
const columns = ref([]);// 从接口加载Excel数据
const loadExcelData = async () => {try {// 1. 请求二进制数据(关键:responseType: 'arraybuffer')const response = await axios.get('https://your-api.com/excel', {responseType: 'arraybuffer'});// 2. 解析Excelconst data = new Uint8Array(response.data);const workbook = XLSX.read(data, { type: 'array' });const firstSheet = workbook.Sheets[workbook.SheetNames[0]];// 3. 提取表头(假设第一行为表头)const headerRow = XLSX.utils.sheet_to_json(firstSheet, { header: 1 })[0];columns.value = headerRow.map(key => ({key,title: key}));// 4. 提取表格数据tableData.value = XLSX.utils.sheet_to_json(firstSheet);} catch (error) {console.error('加载失败:', error);}
};
</script>

 

上传文件获取

此方法适用于excel中单文件,如excel中多文件 请参考上方 封装接口方法


<template><div><el-uploadmultiple:auto-upload="false":on-change="handleFileChange"accept=".xlsx,.xls"><el-button type="primary">选择多个Excel文件</el-button></el-upload><el-table v-for="(table, index) in tables" :key="index":data="table.data"borderstyle="margin-top:20px"><el-table-columnv-for="col in table.columns":key="col.prop":prop="col.prop":label="col.label":formatter="col.formatter"/></el-table></div>
</template><script setup>
import { ref } from 'vue'
import * as XLSX from 'xlsx'const tables = ref([])const handleFileChange = async (files) => {tables.value = []for (const file of files) {const buffer = await file.raw.arrayBuffer()const workbook = XLSX.read(buffer, { type: 'array',cellFormula: true // 保留公式})workbook.SheetNames.forEach(sheetName => {const worksheet = workbook.Sheets[sheetName]const jsonData = XLSX.utils.sheet_to_json(worksheet, {header: 1,raw: false,defval: ""})if(jsonData.length > 0) {const columns = jsonData[0].map((header, idx) => ({prop: `col${idx}`,label: header || `列${idx+1}`,formatter: (row) => {const cellRef = XLSX.utils.encode_cell({r: row.__rowNum__, c: idx})return worksheet[cellRef]?.f ? XLSX.utils.sheet_to_json(worksheet, {header:1})[row.__rowNum__][idx] :row[`col${idx}`]}}))const data = jsonData.slice(1).map((row, rowIndex) => {const rowObj = { __rowNum__: rowIndex + 1 }row.forEach((cell, colIndex) => {rowObj[`col${colIndex}`] = cell})return rowObj})tables.value.push({name: `${file.name}-${sheetName}`,columns,data})}})}
}
</script>

http://www.xdnf.cn/news/13962.html

相关文章:

  • 页面弹窗适配问题
  • Vue权限控制小妙招:动态渲染列表的优雅实现
  • 日常运维问题汇总_43
  • 【Zephyr 系列 23】构建 Web OTA 平台与远程运维工具链:从固件上传到设备在线升级全流程
  • golang使用tail追踪文件变更
  • 解决 Java 与 JavaScript 之间特殊字符传递问题的终极方案
  • ReentrantLock和RLock
  • 新增一个战斗角色
  • n8n实战:自动化生成AI日报并发布
  • USB串口通信、握手协议、深度学习等技术要点
  • window显示驱动开发—为 DirectX VA 2.0 扩展模式提供功能(一)
  • leetcode 2616. 最小化数对的最大差值 中等
  • 【备忘】PHP web项目一般部署办法
  • 《数据安全法》学习(一)
  • 某靶场CTF题目:利用Apache APISIX默认Token漏洞(CVE-2020-13945)获取Flag
  • 2025虚幻角色模型相关笔记
  • Linux用户管理进阶:权限体系深度剖析与实战优化方案
  • 题目类型——左右逢源
  • Python-Flask实现登录
  • PRUD币将于6月16日正式上线欧易Web3交易所,市场热度持续飙升
  • 【Qt/数据结构 QMap是什么类型的数据结构?】
  • 《第一章-初入江湖》 C++修炼生涯笔记(基础篇)C++初识
  • Rust高级抽象
  • Mysql 忘记密码后如何修改
  • 稀土化合物在生态环境的应用
  • 制造业网络安全的挑战与应对策略
  • 德瑞新能源“天佑”车队再征雪域 中尼绿色丝路开启新程
  • 如何在 Android 和 iPhone 上发送群组文本
  • 【常见排序算法】java 代码实现
  • Power Query动态追加查询(对文件夹下文件汇总)