先上效果图:
功能:
- 解析excel文件
- 将解析的数据在表格展示
- 解决表格中存在单元格合并的问题
官网:https://www.npmjs.com/package/xlsx
1、引入插件
-
安装 xlsx 插件
npm i xlsx -S
-
引入
- 直接在当前页面中引用
const xlsx = require("xlsx"); // import xlsx from 'xlsx';
- 全局使用
// main.js import Vue from 'vue'; import xlsx from 'xlsx'; Vue.prototype.$xlsx = xlsx;
-
可以通过引入 CDN 的方式
<script src="https://unpkg.com/xlsx/dist/xlsx.full.min.js"></script>
2、解析文件
-
基本使用
可以去node_modules/xlsx目录下查看相关的文档,里面非常详细的说明了该插件的使用(解析本地excel文件、解析远程返回的excel文件等),包含了使用的例子。
xlsx 的 read 方法:(注意 options 的参数类型)
function read(blob, options) { switch(options && options.type || "base64") { case "file": return read_file(blob, options); case "base64": return parse(s2a(Base64.decode(blob)), options); case "binary": return parse(s2a(blob), options); } return parse(blob, options); }
具体的解析原理我也没看懂太多,就不赘述了。
-
做简单封装
- 解析excel文件
const { read } = require("xlsx"); // 获取解析后的数据 exports.showxlsx = function( data , type = "readAsBinaryString" , options = { type: "binary"} ) { return new Promise( (resolve,reject) => { const file = new FileReader(); file[type](data); // 加载事件 file.onload = function(e){ let result = e.target.result; // 获取文件内容 try { resolve(read(result , options));} catch (error) { reject(error); } } }) }
- 处理解析得到的数据
exports.parse = function(params) { let SheetNames = params.SheetNames[0]; if(!SheetNames) throw new Error("params error !"); let obj = {...params.Sheets[SheetNames]}; if(!obj) throw new Error(`${SheetNames} error !`); let res = {} , merge = [] , header = []; // 主要数据 , 合并信息 , 表头 Object.keys(obj).map( v => { // 暂时不明确作用,先去除 if(v == "!margins" || v == "!ref") return ; // 获取合并的信息 if(v == "!merges") { obj[v].map( item => { merge.push(getMergeMessage(item)); }) return ; } // 存储每一行的信息 let [row , number] = [v.split("").slice(0,1) , v.split("").slice(1).join("")]; !res[row] && (res[row] = []); res[row][number] = obj[v]["v"]; }) for(let k in res){ if(!(/[a-zA-Z]/.test(k))) continue; header.push({ prop: k, label: k }) // 表头数据(A-Z) } return { header, data: res, merge: merge[0], } } // 获取合并信息 function getMergeMessage(obj) { let result = [] Object.keys(obj).map( v => { result.push([obj[v].r,obj[v].c]); }) return result; }
3、展示数据
-
封装表格组件(略)
-
通过 el-upload 获取 file 信息(监听 on-change )(略)
-
on-change 事件 (前提:先引入上述方法)
// 获取 excel 文件数据 onchange(file) { this.loading = true; showxlsx(file).then((res) => { let result = parse(res); this.tableHeader = result.header; this.tableData = []; let max = Math.max.apply( "", this.tableHeader.map((v) => { return result.data[v.label].length; }) ); // 由于 data 记录的每一列的数据,需要进行处理 for (let i = 0; i < max; i++) { this.tableData[i] = {}; this.tableHeader.map((v) => { this.tableData[i][v.label] = result.data[v.label][i] || ""; }); this.tableData = this.tableData.filter((v) => { return Object.values(v).filter((val) => val).length > 0; }); } this.$nextTick(() => { this.$refs.mtable.$refs.mTable.doLayout(); // 解决表格信息错乱 this.loading = false; }); this.merge = [...result.merge]; // 传给表格组件的表格合并数据 }); },
4、解决单元合并
-
表格组件
<el-table :ref="refName" :show-header="showHeader" :span-method="arraySpanMethod" >...</el-table> <script> export default { props: { // 合并的数据 mergeTable: { type: Array, default: function() { return []; }, } } }, methods: { // 增加表格合并 arraySpanMethod({ rowIndex }) { if(!this.merge.length) return ; let arr = this.mergeTable.map( v => { let [r , c] = v; // 行 列 if(rowIndex == r) return Number(c) + 1; }).filter( v => v); return arr.length?arr:""; }, } </script>