论如何优雅的用Vue从前台导入excel(并处理单元格合并问题)
最近接到一个需求 导入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(并处理单元格合并问题)相关推荐
- 使用vue,实现前端导入excel数据
文章目录 前言 一.引入组件 二.封装导入功能的组件 1.编写组件template 2.获取数据 3.调用接口把数据传给后端 三.总结 前言 继前边的vue的导出功能后,自己又去在网上搜了vue导入e ...
- 使用Vue,Element-ui导入Excel并预览显示数据,并经数据保存传至后台数据库
需求:基于Vue,Element-ui框架,将本地Excel上传,并将表格中的数据绑定显示在上传页面,并保存提交到后台数据库 此功能在做的时候网上有很多的案例,但是都是基于Export2Excel.j ...
- vue 导出excel,支持单元格合并,背景色,列宽,字体大小等
npm下载 npm i xlsx.full.min npm i xlsx-style 关键代码如下 downloadExl(data, name, datab) {const wopts = {boo ...
- vue项目element-ui的table表格单元格合并
一.合并效果 二全部代码 <template><div class="table-wrap"><el-table:data="tableDa ...
- Vue+Element前端导入导出Excel
1 前言 1.1 业务场景 由前台导入Excel表格,获取批量数据. 根据一个数组导出Excel表格. 2 实现原理 2.1 引入工具库 file-saver.xlsx.script-loader n ...
- VUE实现前台图片 标注(添加矩形框)、放大、缩小、拖拽 -----个人记录
VUE实现前台图片 标注(添加矩形框).放大.缩小.拖拽 需求:实现图片上自定义多个矩形选框,选框可移动缩放拖动,图片可以放大缩小.拖拽 ,选框内填充标注文字. 框内填充文字基本都会,不多赘述,后期可 ...
- Vue.js前台报Uncaught (in promise) cancel错误解决办法
今天做一个demo时碰到了Vue.js前台报Uncaught (in promise) cancel的错误,虽然不影响操作但是看见了心里不爽,于是在网上找了一些资料,总结如下 原因: this.$co ...
- 基于vue.js前台美食点菜订餐系统ssm java毕业设计项目有介绍
一.源码描述 这是一款前后端分离的SSM和vue.js源码,开发工具:idea,也支持eclipse,数据库:MySQL功能也比较全面,比较适合作为毕业设计使用,感兴趣的朋友可以下载看看哦 二.功 ...
- vue中如何进行Excel文件的下载
文章目录 业务需求: 实现方式 A1.模板下载: A2.搜索下载: A3.勾选下载: A4.上传错误记录下载Excel文件 业务需求: Q1.文件批量导入前,需要按照指定的格式与内容上传Excel文件 ...
最新文章
- python画圆形螺旋线_这个Python项目,一秒生成可爱像素风图片
- find命令--Linux命令应用大词典729个命令解读
- PIC32单片机harmony开发环境 - i2c例程和代码分析
- spark官方文档_这些未在 Spark SQL 文档中说明的优化措施,你知道吗?
- Kubernetes-[6]-StatefulSet
- POJ 3744:Scout YYF I 概率DP+特征方程+快速幂
- .NetCore Session.Redis
- 《绯雨骑士团》Demo
- python控制电机转动_使用python,通过串口ROS直接控制电机驱动器(6)
- linux mbr转gpt分区,linux将GPT分区转换为MBR、RHEL GPT报错
- 基于easyx低配版flappybird
- C语言刷题随记 —— 国际象棋棋盘
- 主板电容损坏导致台式机开机风扇转无显示信号输出
- 思岚科技再次出征CES 看点十足
- android 实现漫天飞舞雪花以及下雨天的效果
- SharedPreferences 使用方法详解
- html 单选 lable,label 标签的用法,点label选中单选、复选框或文本框
- onload和ready的不同
- 「数据库选型」抛弃MongoDB,拥抱PostgreSQL,工作更轻松
- Requests+Etree+BeautifulSoup+Pandas+Path+Pyinstaller应用 | 获取页面指定区域数据存入html、excel文档