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

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>

相关文章:

  • Java + easyexcel 新旧数据对比,单元格值标红
  • 穿越时空的刀剑之旅:走进VR刀剑博物馆​
  • 720云vr全景怎么制作?720全景制作费用?
  • PHP基础-控制结构
  • 【Zephyr 系列 22】从单机开发到平台化:构建你自己的 Zephyr 物联网开发平台
  • 实战案例-JESD204B 多器件同步
  • 网络原理:网段划分
  • 北斗导航 | 基于MATLAB的卫星导航单点定位算法(卡尔曼滤波增强)
  • 对称加密和非对称加密
  • Python 数据分析10
  • 【Python 进阶系列】第4篇:初探 Python Pandas 数据分析的世界
  • 大模型驱动数据分析革新:美林数据智能问数解决方案破局传统 BI 痛点
  • 【60 Pandas+Pyecharts | 箱包订单数据分析可视化】
  • Spring Boot自动配置原理与实践
  • 一文掌握 Windows 文件传输:5 种命令行工具的原理、参数与示例
  • UR机器人解锁关节扭矩控制:利用英伟达Isaac Lab框架,推动装配自动化的Sim2Real迁移
  • electron-builder打包配置(应用名、安装包、图标、快捷方式、自定义文件关联启动等)
  • 全新RA2L2 MCU超低功耗、支持CAN及USB-C、拓展工业及便携式应用
  • 护城河尚浅,理想汽车驶入慢车道
  • torch 高维矩阵乘法分析,一文说透
  • 厦门网站改版/网络广告代理
  • 做海报可以在哪些网站下载素材/阿里巴巴logo
  • 保定网站建设技术支持/营销推广手段有什么
  • 网站后台无法审核/线上推广网络公司
  • wordpress jquery版本/优化大师破解版app
  • 成都网站建设sm1010/新乡seo公司