最近接到一个需求 导入excel后还要进行编辑再保存,所以采用了前台导入的方式,使用的xlsx

假设表格是这样的

第一步 使用input组件进行文件上传

<span><input ref="fileInput" type="file" @change="fileChangeHandle" style="display: none;"><el-button type="primary" size="small" icon="el-icon-folder-add" @click="clickHandle"><slot></slot></el-button>
</span>
clickHandle() {this.$refs.fileInput.click()
},
fileChangeHandle(e) {let file = this.$refs.fileInput.files[0];// 通过DOM取文件数据let formData = new FormData();//new一个formData事件formData.append("file", file)this.$emit('changeHandle', {data: formData, clear: () => e.target.value = null, file: file})
}

这样就拿到了上传的文件

第二步 使用xlsx读取文件,并对合并的单元格进行处理

read(sheet, cbk) {//拿到所导入文件的名字const fileName = this.file//定义reader,存放文件读取方法const reader = new FileReader()//启动函数reader.readAsBinaryString(fileName)//onload在文件被读取时自动触发reader.onload = (e) => {//workbook存放excel的所有基本信息const workbook = XLSX.read(e.target.result, {type: 'binary'});//定义sheetList中存放excel表格的sheet表,就是最下方的tablet worksheet = workbook.Sheets[workbook.SheetNames[sheet]]; // 只能通过工作表名称来获取指定工作表this.excelData = worksheetthis.initMerge() //初始化合并单元格信息cbk(this)}}initMerge() {const merges = this.excelData['!merges'];merges.forEach(p => {let columnIndex = p['s']['c']const endColumn = p['e']['c']let rowIndex = p['s']['r']const endRow = p['e']['r']const startColumn = String.fromCharCode(A + p['s']['c'])const startRow = p['s']['r'] + 1while (columnIndex <= endColumn) {rowIndex = p['s']['r']while (rowIndex <= endRow) {let column = String.fromCharCode(A + columnIndex);let row = rowIndex + 1this.mergeMap[column + row] = this.excelData[startColumn + startRow]['v']rowIndex++}columnIndex++}})}

excel 默认合并的单元格只会保留第一格的值,进行处理后将所有值存入了变量mergeMap

打印一下处理好的合并单元格map

第三步 数据提取

参数:

titleLine: 标题行

startRow:数据开始行

startColumn:数据开始列

alias:别名 传入一个AliasMap对象

toArray(titleLine = 1, startRow = 1, startColumn = 'A', alias = null) {if (this.excelData == null || !this.excelData) {return []}const resultArr = []const length = this.excelData['!rows'].lengthfor (let i = startRow; i < length; i++) {const item = {}let column = startColumndo {//拿到属性名 如果没有就去合并单元格里面找let attrName = ''if(this.excelData[column + titleLine]) {attrName = this.excelData[column + titleLine]['v']} else {attrName = this.mergeMap[column + titleLine]}//如果设置了别名if (alias != null) {let prev = ''if (alias.prevLine && alias.prevLine > 0) {prev = this.mergeMap[column + alias.prevLine] + '-'}attrName = alias.getAlias(prev + attrName)}if(this.excelData[column + i]) {item[attrName] = this.excelData[column + i]['v']} else {item[attrName] = ''}column = this.chartAdd(column)} while (this.excelData[column + titleLine])resultArr.push(item)}return resultArr}

这里我进行了取别名的操作 因为excel里面读取的是汉字 将属性名映射为对应的字段名

const map = {'班级': 'banji','语文': 'yuwen','数学': 'shuxue','英语': 'yingyu','计算机基础': 'jisuanjijichu','算法': 'suanfa','数据结构': 'shujujiegou'}e.toArray(3, 4, 'A', new AliasMap(map));

打印一下读取结果

但是这还不够,有时候会有这样的表格

这样他的表头会有重复的时候,只需要构建别名时加入前缀即可

读取结果:

完整代码:

import XLSX from "xlsx";/*** Excel读取类* @author: Savitar* @datetime: 2021-10-14*/const A = 65export class ExcelReader {constructor(file, sheet, cbk) {this.file = filethis.excelData = nullthis.mergeMap = {}this.read(sheet, cbk)}read(sheet, cbk) {//拿到所导入文件的名字const fileName = this.file//定义reader,存放文件读取方法const reader = new FileReader()//启动函数reader.readAsBinaryString(fileName)//onload在文件被读取时自动触发reader.onload = (e) => {//workbook存放excel的所有基本信息const workbook = XLSX.read(e.target.result, {type: 'binary'});//定义sheetList中存放excel表格的sheet表,就是最下方的tablet worksheet = workbook.Sheets[workbook.SheetNames[sheet]]; // 只能通过工作表名称来获取指定工作表this.excelData = worksheetthis.initMerge()cbk(this)}}/*** 初始合并单元格* excel合并单元格后默认只有左上角的单元格保留值 此方法会将所有合并的单元格都赋值*/initMerge() {const merges = this.excelData['!merges'];if(!merges) returnmerges.forEach(p => {let columnIndex = p['s']['c']const endColumn = p['e']['c']let rowIndex = p['s']['r']const endRow = p['e']['r']const startColumn = createCol(p['s']['c'])const startRow = p['s']['r'] + 1while (columnIndex <= endColumn) {rowIndex = p['s']['r']while (rowIndex <= endRow) {let column = createCol(columnIndex);let row = rowIndex + 1this.mergeMap[column + row] = this.excelData[startColumn + startRow]['v']rowIndex++}columnIndex++}})}toArray(titleLine = 1, startRow = 1, startColumn = 'A', alias = null, endRow = 999) {if (this.excelData == null || !this.excelData) {return []}const resultArr = []let length;if(this.excelData['!rows'] && this.excelData['!rows'].length) {length = this.excelData['!rows'].length} else {length = endRow;}for (let i = startRow; i <= length; i++) {const item = {}let column = startColumnlet columnIndex = startColumn.charCodeAt()do {//拿到属性名let attrName = ''if (this.excelData[column + titleLine]) {attrName = this.excelData[column + titleLine]['v']} else {attrName = this.mergeMap[column + titleLine]}//如果设置了别名if (alias != null) {let prev = ''if (alias.prevLine && alias.prevLine > 0) {prev = this.mergeMap[column + alias.prevLine] + '-'}attrName = alias.getAlias(prev + attrName)}if (this.excelData[column + i]) {item[attrName] = this.excelData[column + i]['v']} else {item[attrName] = ''}column = this.chartAdd(columnIndex)columnIndex++} while (this.excelData[column + titleLine])resultArr.push(item)}return resultArr}chartAdd(columnIndex) {return createCol(columnIndex - A)}
}function createCol(n) {const ordA = 'A'.charCodeAt(0)const ordZ = 'Z'.charCodeAt(0)const len = ordZ - ordA + 1let str = ""while (n >= 0) {str = String.fromCharCode(n % len + ordA) + strn = Math.floor(n / len) - 1}return str
}/***** @param file* @param sheet* @param cbk*//**** 别名map*/
export class AliasMap {constructor(map = {}, prevLine) {this.map = map;this.prevLine = prevLine}getAlias(name) {return this.map[name] || name}}

论如何优雅的用Vue从前台导入excel(并处理单元格合并问题)相关推荐

  1. 使用vue,实现前端导入excel数据

    文章目录 前言 一.引入组件 二.封装导入功能的组件 1.编写组件template 2.获取数据 3.调用接口把数据传给后端 三.总结 前言 继前边的vue的导出功能后,自己又去在网上搜了vue导入e ...

  2. 使用Vue,Element-ui导入Excel并预览显示数据,并经数据保存传至后台数据库

    需求:基于Vue,Element-ui框架,将本地Excel上传,并将表格中的数据绑定显示在上传页面,并保存提交到后台数据库 此功能在做的时候网上有很多的案例,但是都是基于Export2Excel.j ...

  3. vue 导出excel,支持单元格合并,背景色,列宽,字体大小等

    npm下载 npm i xlsx.full.min npm i xlsx-style 关键代码如下 downloadExl(data, name, datab) {const wopts = {boo ...

  4. vue项目element-ui的table表格单元格合并

    一.合并效果 二全部代码 <template><div class="table-wrap"><el-table:data="tableDa ...

  5. Vue+Element前端导入导出Excel

    1 前言 1.1 业务场景 由前台导入Excel表格,获取批量数据. 根据一个数组导出Excel表格. 2 实现原理 2.1 引入工具库 file-saver.xlsx.script-loader n ...

  6. VUE实现前台图片 标注(添加矩形框)、放大、缩小、拖拽 -----个人记录

    VUE实现前台图片 标注(添加矩形框).放大.缩小.拖拽 需求:实现图片上自定义多个矩形选框,选框可移动缩放拖动,图片可以放大缩小.拖拽 ,选框内填充标注文字. 框内填充文字基本都会,不多赘述,后期可 ...

  7. Vue.js前台报Uncaught (in promise) cancel错误解决办法

    今天做一个demo时碰到了Vue.js前台报Uncaught (in promise) cancel的错误,虽然不影响操作但是看见了心里不爽,于是在网上找了一些资料,总结如下 原因: this.$co ...

  8. 基于vue.js前台美食点菜订餐系统ssm java毕业设计项目有介绍

    一.源码描述   这是一款前后端分离的SSM和vue.js源码,开发工具:idea,也支持eclipse,数据库:MySQL功能也比较全面,比较适合作为毕业设计使用,感兴趣的朋友可以下载看看哦 二.功 ...

  9. vue中如何进行Excel文件的下载

    文章目录 业务需求: 实现方式 A1.模板下载: A2.搜索下载: A3.勾选下载: A4.上传错误记录下载Excel文件 业务需求: Q1.文件批量导入前,需要按照指定的格式与内容上传Excel文件 ...

最新文章

  1. python画圆形螺旋线_这个Python项目,一秒生成可爱像素风图片
  2. find命令--Linux命令应用大词典729个命令解读
  3. PIC32单片机harmony开发环境 - i2c例程和代码分析
  4. spark官方文档_这些未在 Spark SQL 文档中说明的优化措施,你知道吗?
  5. Kubernetes-[6]-StatefulSet
  6. POJ 3744:Scout YYF I 概率DP+特征方程+快速幂
  7. .NetCore Session.Redis
  8. 《绯雨骑士团》Demo
  9. python控制电机转动_使用python,通过串口ROS直接控制电机驱动器(6)
  10. linux mbr转gpt分区,linux将GPT分区转换为MBR、RHEL GPT报错
  11. 基于easyx低配版flappybird
  12. C语言刷题随记 —— 国际象棋棋盘
  13. 主板电容损坏导致台式机开机风扇转无显示信号输出
  14. 思岚科技再次出征CES 看点十足
  15. android 实现漫天飞舞雪花以及下雨天的效果
  16. SharedPreferences 使用方法详解
  17. html 单选 lable,label 标签的用法,点label选中单选、复选框或文本框
  18. onload和ready的不同
  19. 「数据库选型」抛弃MongoDB,拥抱PostgreSQL,工作更轻松
  20. Requests+Etree+BeautifulSoup+Pandas+Path+Pyinstaller应用 | 获取页面指定区域数据存入html、excel文档

热门文章

  1. 子桓说:学几招商业套路,以后用的上!
  2. 打印订单--bcty365
  3. 【移动安全实战篇】————5、Android屏幕解锁图案破解
  4. 计算机毕业设计ssm财务报账管理系统l6tbn系统+程序+源码+lw+远程部署
  5. 贷后催收评分模型中的数据清洗与数据治理细节介绍
  6. c语言能做安卓游戏吗,c语言能编写手机游戏吗?
  7. android studio获取IMEI码
  8. java写入文件不覆盖,斩获offer
  9. 微信小程序计算三角形面积
  10. [Excel VBA]判斷英文字母是否為大寫