实现导入、导出、存储、回显
项目地址:https://gitee.com/fei-feather-all-over-the-sky/lucksheet-use
将lucksheet表格数据以elementui格式呈现
效果图:
前提 是拿到lucksheet保存的excel格式文件 ,再通过sheetjs解析
sheetjs:https://github.com/SheetJS/sheetjs#the-zen-of-sheetjs
1.单独拿到表头数据
主要是给数据添加label 和prop属性 用来在table中显示
获取到后台返回的表头数据后,二次处理格式调用以下方法;如果不确定级别可以使用递归来写;使用titleArr盛放 末级表头,用于表格内容与表头一一对应。
/* 操作表头 */
handleTitle(arr){
arr.forEach(item=>{
item.label = item.title;
item.prop = `prop${item.id}`;
if(!item.child || item.child.length===0){
this.titleArr.push(`prop${item.id}`)
}
if(item.child && item.child.length>0){
this.handleTitle(item.child);
}
})
},
//数据格式
[
{
"title": "a",
"id": 1,
"child": [
{
"title": "a1",
"id": 2
}
]
},
{
"title": "b",
"id": 3,
"child": [
{
"title": "b1",
"id": 4
}
]
}
]
2.处理除表头外其他数据
解析为一行一行的数据,再处理合并信息,我们拿到的是一个Excel表格,所以得先解析数据。接收来得是blob格式数据。此代码中把表头固定为2行做的。
getExcelFile(res){
let _this = this;
let fileName = "实验室测试数据.xlsx"
if(res.headers["content-disposition"]){
fileName = res.headers["content-disposition"].split("=")[1];
}
fileName = decodeURI(fileName); //文件名称解码
fileName = fileName.replace(/\+/g, ""); //文件名称修改
let a = fileName.split('.');
this.excelTitle = a[0]; //文件名称
let file = new File([res.data], fileName);
const reader = new FileReader();
reader.readAsBinaryString(file); //以二进制读取
reader.onload = function(){
const excelFile = XLSX.read(this.result, { //sheetjs插件
type: 'binary'
});
console.log("====excelFile====",excelFile);
_this.resultData = _this.handleData(excelFile.Sheets,_this.titleArr)
console.log("====this.resultData====",_this.resultData);
}
},
/* 整理表格内容 */
handleData(sheets,title) {
let sheetsFinal = []
let sheetsKeys = Object.keys(sheets)
for (let i = 0; i < sheetsKeys.length; i++) {
let sheet = sheets[sheetsKeys[i]]
const arr = [];
this.handleMerge(sheet['!merges'],arr)
this.excelMergeData.push(arr); // 合并数据
console.log(this.excelMergeData,"====excelMergeData")
sheetsFinal.push(
{
sheetName:sheetsKeys[i],
data:this.handleSheet(sheet,title)
}
)
}
return sheetsFinal
},
/* 将数据按行解析出来 */
handleSheet(sheet,title) {
const heardRows = 2; //表头行数
let sheetDataArr = []; //每个工作表的数据
if(!sheet['!ref']){
return sheetDataArr
}
let totleRows = this.screenRows(sheet); //有效行
let columnArr = this.screenColumn(sheet); //有效列
if(title && title.length>0 && title.length!==columnArr.length){
// alert("标题列数与内容列数不符")
return []
}
for (let i = heardRows+1; i <= totleRows; i++) { /* 循环行 只循环除表头之外的数据 heardRows:表头所占行数*/
let obj = {};
for (let j = 0; j < columnArr.length; j++) { /* 循环列 */
let key = title && title.length>0?title[j]:columnArr[j];
if (sheet[columnArr[j] + i]) {
obj[key] = sheet[columnArr[j] + i].w;
}else{
obj[key] = "";
}
}
sheetDataArr.push(obj)
}
return sheetDataArr
},
/* 处理合并信息 */
handleMerge(merge,arr){
if(!merge){
return
}
merge.forEach((item,index)=>{
const start = item.s;
const end = item.e;
if(start.r>1){
start.r = start.r - 2; // 减去前两行标题
end.r = end.r - 2; // 减去前两行标题
const key = `${start.c}_${start.r}`; "列_行"
const obj1 = {}
obj1[key] = {
cs: end.c - start.c===0?1:end.c - start.c+1, //列合并数
rs: end.r - start.r===0?1:end.r - start.r+1, //行合并数
}
arr.push(obj1)
for(let i=start.r+1;i<end.r+1;i++){ //合并时需要去掉的单元格 按行
const key = `${start.c}_${i}`; "列_行"
const obj1 = {}
obj1[key] = {
cs: 0, //列合并数
rs: 0, //行合并数
}
arr.push(obj1)
}
for(let i=start.c+1;i<end.c+1;i++){ //合并时需要去掉的单元格 按列
const key = `${i}_${start.r}`; "列_行"
const obj1 = {}
obj1[key] = {
cs: 0, //列合并数
rs: 0, //行合并数
}
arr.push(obj1)
}
}
})
},
/* 整理出有效列 : 即如果没有数据则不统计*/
screenColumn(sheet){ //过滤列
let sheetKeys = Object.keys(sheet)
let columnArr = []
if(!sheet['!ref']){
return columnArr;
}
let range = XLSX.utils.decode_range(sheet['!ref'])
for (let c = range.s.c; c <= range.e.c; c++) {
const columnName = XLSX.utils.encode_col(c);
const isExist = sheetKeys.some(item=>{
return item.replace(/[1-9]/g,"")==columnName
})
if(!isExist){
break;
}
columnArr.push(columnName)
}
return columnArr;
},
/* 整理出有效行 : 即如果没有数据则不统计*/
screenRows(sheet){
let sheetKeys = Object.keys(sheet)
let totleRows=0;
const reg = /[1-9]/g;
for(let key of sheetKeys){
if(key.indexOf("!")==-1){
const number = key.match(reg)?key.match(reg).join("")*1:0;
totleRows = Math.max(totleRows,number);
}
}
return totleRows
}
3.页面显示
依靠table的 span-method
<div v-if="resultData || resultData.length>0" v-for="(sheet,index) in resultData" :key="index">
<div v-if="resultData.length>1" style="padding: 10px;color:#495BA6;font-weight: 700">
{{sheet.sheetName}}
</div>
<el-table class="mytable"
:data="sheet.data" :header-cell-style="{borderColor:'#AE91F5',color:'#6649A6',background:'#E1E7FF'}" :cell-style="{borderColor:'#CED4EB',color:'#333'}" :span-method="objectSpanMethod(index)" border
style="width: 100%">
<el-table-column v-for="(item,index) in excelTableTitles" :key="Math.random()" align="center" min-width="120"
:prop="item.prop"
:label="item.label"
>
<el-table-column v-for="(val,index) in item.child" :key="Math.random()" align="center" min-width="120"
:prop="val.prop"
:label="val.label"
>
<el-table-column v-for="(val1,index) in val.child" :key="Math.random()" align="center" min-width="120"
:prop="val1.prop"
:label="val1.label"
>
</el-table-column>
</el-table-column>
</el-table-column>
</el-table>
</div>
objectSpanMethod(index) {
return ({ row, column, rowIndex, columnIndex })=>{
const arr = this.excelMergeData[index];
const key = `${columnIndex}_${rowIndex}`;
if(arr.length>0){
let flag = false;
for(let item of arr){
console.log(key,item)
if(item[key]){
flag=true;
console.log(key,[item[key].rs,item[key].cs])
return [item[key].rs,item[key].cs] // [行合并数,列合并数]
}
}
if(!flag){
return [1,1]
}
}
else{
return [1,1]
}
}
},