最近有个功能需要将excel展示到html 界面里面,看是简单的一个需求也是需要费尽心思才完得成
原始数据
想要把excel 读取出来,于是使用xlsl的插件
npm i xlsx
通过插件可以获取到已经分析好的数据
然后使用sheet_to_html
将数据转换为html 再使用v-html加载数据
<div v-html="rowsHtml"class="continertable"></div>
预览效果
由于行列内容太多看起来有些乱,这效果的确不是想要的,于是想到了使用element ui 的table 来加载
于是根据这个案例开始重新组织xlsx 加载返回的数据
首先要将数据行列重新组装
dealTableData (worksheet) {// const worksheet = workbook.Sheets[sheetNames[0]];// 拿到这张表中表格数据的范围,const range = utils.decode_range(worksheet['!ref']);// console.log(worksheet['!ref']); // A1:E5//保存数据范围数据const row_start = range.s.r; // 表格范围,开始行的数据const row_end = range.e.r; // 表格范围,结束行的数据const col_start = range.s.c; // 表格范围,开始列的数据const col_end = range.e.c; // 表格范围,结束行的数据const tableMerge = worksheet['!merges'] || []; // 表格中进行单元格合并操作的数据var oo = [];var tableArr = []; // 存储所以的td 数组var preamble = "<tr>"; // 转 html 时进行拼接// let rows = [], row_data, i, addr, cell;//按行对 sheet 内的数据循环//首先读取当前对象内的所有行数据,从开始到结束for (var R = row_start; R <= row_end; ++R) {var innerRow = []var innerRowJson = []// out.push(make_html_row(ws, r, R, o));// 读取列数据,开始到结束省略部分................// 组装表头this.assemblyTableData(tableArr);this.asseblyTableColumn(tableArr);},
再是组装行列,增加asseblyTableColumn
方法
这里由于是多级表头,所以需要一个二维数组
// 组装一个表单类字段asseblyTableColumn (arr) {const firstArr = arr[0];const secondArr = arr[1];const thirdArr = arr[2];const secondChildren = []let thirdObj = {}const thirdChildren = []// 数组第一个为表头const resArr = [{label: firstArr[0]['name'],...firstArr[0]}];thirdArr.forEach(e => {let propStr = e.id.match(propRegex)thirdChildren.push({label: e.name,prop: propStr[0],...e})})secondArr.forEach(e => {let propStr = e.id.match(propRegex)// 包含colspan为下一个表头if (e.hasOwnProperty('colspan')) {thirdObj = {label: this.removeHTMLTags(e.name),...e,children: thirdChildren,}} else {secondChildren.push({label: e.name,prop: propStr[0],...e})}})secondChildren['children'] = [thirdObj];resArr[0]['children'] = secondChildren;this.tableHeadArr = resArr},
再增加一个重构表单数据的方法assemblyTableData
assemblyTableData (arr) {this.categoryCN = [];/*** 合并信息* [{* rowNum:0,* colNum:0,* rowspan:0,* colspan:0,* }]*/const spInfo = [];this.resTableData = [];// 从第三一个开始for (let i = 3; i < arr.length; i++) {let eachObj = {}let rowcolObj = {}arr[i].forEach(e => {let propStr = e.id.match(propRegex)eachObj[propStr[0]] = this.removeHTMLTags(e.name);const colName = propStr[0].match(/\w$/)[0];const rowNum = e.id.match(rowNumRegex)[0]if (e.hasOwnProperty('rowspan') && e.hasOwnProperty('colspan')) {spInfo.push({rowspan: e['rowspan'],colspan: e['colspan'],rowNum,colNum: colNumArr.findIndex(e => e === colName)})} else if (e.hasOwnProperty('rowspan')) {spInfo.push({rowspan: e['rowspan'],rowNum,colNum: colNumArr.findIndex(e => e === colName)})} else if (e.hasOwnProperty('colspan')) {spInfo.push({colspan: e['colspan'],rowNum,colNum: colNumArr.findIndex(e => e === colName)})}})this.resTableData.push(eachObj)}const categoryCN = this.categoryCN;// 根据colNum进行分组,便于合并spInfo.forEach(cn => {if (categoryCN[cn.colNum]) {categoryCN[cn.colNum].push(cn)} else {categoryCN[cn.colNum] = [cn];}})
省略部分......},
最后效果
看起来是要好很多了,接下来就是进行行列合并的操作了
待续…