在实际开发场景中,有些表格只单单依靠前端就可以实现表格导入导出的功能,以下是案例详情:
须注意事项!!!!
- 前端实现导出表格只针对没有分页的表格,只能导出页面展示的表格(由于仅靠前端完成功能,没有调用接口,因此数据库的自然无法导出)
- 此次案例的导出功能只针对表格样式较为简单的表格(合并表格的还没做好)
- 只针对xlsx、xls格式的文件
- 使用vue2+element
功能动图预览
导入导出功能
页面部分
- 使用了elelment的上传组件(模板部分)
<el-upload
class="upload-demo"
action=""
ref="upload"
:on-change="handleChange"
:file-list="fileListUpload"
:limit="1"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel"
:auto-upload="false"
>
<el-button size="small" type="primary">导入表格预览</el-button>
<div slot="tip" class="el-upload__tip">
只 能 上 传 xlsx / xls 文 件
</div>
</el-upload>
<el-button size="small" type="primary" @click="doExport"
>导出</el-button
>
<div id="tableHtml"></div>
- js部分使用了
- xlsx插件,
npm i xlsx -D 或者 yarn add xlsx -D
- xlsxFile方法,js方法
<script>
import download from '@/utils/xlsxFile'
export default {
name: "LabProjectIndex",
data() {
return {
outdata:null,
fileListUpload: [],
outdataExport:[],
fileTemp:{}
};
},
mounted() {},
methods: {
doExport(e) {
download(this.outdataExport,'测试数据.xlsx')//导出的文件名
},
handleChange(file, fileList) {
this.fileTemp = file.raw;
if (this.fileTemp) {
if (
this.fileTemp.type ==
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ||
this.fileTemp.type == "application/vnd.ms-excel"
) {
this.importfxx(this.fileTemp);
this.$refs.upload.clearFiles();
} else {
this.$message({
type: "warning",
message: "附件格式错误,请删除后重新上传!",
});
}
} else {
this.$message({
type: "warning",
message: "请上传附件!",
});
}
},
importfxx(obj) {
let _this = this;
// 通过DOM取文件数据
this.file = obj;
let rABS = false; //是否将文件读取为二进制字符串
let f = this.file;
let reader = new FileReader();
//if (!FileReader.prototype.readAsBinaryString) {
FileReader.prototype.readAsBinaryString = function (f) {
let binary = "";
let rABS = false; //是否将文件读取为二进制字符串
let wb; //读取完成的数据
let reader = new FileReader();
reader.onload = function (e) {
let bytes = new Uint8Array(reader.result);
let length = bytes.byteLength;
for (let i = 0; i < length; i++) {
binary += String.fromCharCode(bytes[i]);
}
console.log(binary, "binarybinary");
let XLSX = require("xlsx"); //使用了xlsx插件,需要yarn add xlsx 或者 npm i xlsx
if (rABS) {
wb = XLSX.read(btoa(fixdata(binary)), {
//手动转化
type: "base64",
});
} else {
wb = XLSX.read(binary, {
type: "binary",
});
}
// this.outdata = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]); //转换为数据(数组对象)
// 将读取到的数据转换成html
this.outdata = XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]); //转换为html
console.log( this.outdataExport)
document.querySelector("#tableHtml").innerHTML = this.outdata;
_this.outdataExport = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]); //转换数据
// this.tableToHtml(XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]))
// console.log(this.outdata, "outdataoutdata");
};
reader.readAsArrayBuffer(f);
};
if (rABS) {
reader.readAsArrayBuffer(f);
} else {
reader.readAsBinaryString(f);
}
},
},
};
</script>
xlsxFile.js
import * as xlsx from 'xlsx'
export default function download(json,fileName){
const type = 'xlsx'//定义导出文件的格式
var tmpDown;//导出的内容
var tmpdata = json[0];
json.unshift({});
var keyMap = []; //获取keys
for (var k in tmpdata) {
keyMap.push(k);
json[0][k] = k;
}
var tmpdata = [];//用来保存转换好的json
json.map((v, i) => keyMap.map((k, j) => Object.assign({}, {
v: v[k],
position: (j > 25 ? getCharCol(j) : String.fromCharCode(65 + j)) + (i + 1)
}))).reduce((prev, next) => prev.concat(next)).forEach((v, i) => tmpdata[v.position] = {
v: v.v
});
var outputPos = Object.keys(tmpdata); //设置区域,比如表格从A1到D10
var tmpWB = {
SheetNames: ['mySheet'], //保存的表标题
Sheets: {
'mySheet': Object.assign({},
tmpdata, //内容
{
'!ref': outputPos[0] + ':' + outputPos[outputPos.length - 1] //设置填充区域
})
}
};
tmpDown = new Blob([s2ab(xlsx.write(tmpWB,
{bookType: (type == undefined ? 'xlsx':type),bookSST: false, type: 'binary'}//这里的数据是用来定义导出的格式类型
))], {
type: ""
}); //创建二进制对象写入转换好的字节流
saveAs(tmpDown,fileName);
}
function saveAs(obj, fileName){//导出功能实现
var tmpa = document.createElement("a");
tmpa.download = fileName || "下载";
tmpa.href = URL.createObjectURL(obj); //绑定a标签
tmpa.click(); //模拟点击实现下载
setTimeout(function () { //延时释放
URL.revokeObjectURL(obj); //用URL.revokeObjectURL()来释放这个object URL
}, 100);
}
function s2ab(s){ //字符串转字符流
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
}
function getCharCol(n){
let temCol = '',
s = '',
m = 0
while (n > 0) {
m = n % 26 + 1
s = String.fromCharCode(m + 64) + s
n = (n - m) / 26
}
return s
}
导入部分功能实现,将xlsx的方法读取导入文件的数据,然后将其转换为html,然后将其赋值给dom的innerHTML:
document.querySelector("#tableHtml").innerHTML = this.outdata;
导出部分功能实现,在导入表格时,将导入的表格读取转换为数据,赋值给全局变量,然后再点击导出时调用xlsxFile方法
document.querySelector("#tableHtml").innerHTML = this.outdata;
开发中遇到的问题
1.element的upload上传组件在上传文件后需要将文件清除,否则无法重新上传
this.$refs.upload.clearFiles();
2.在使用XLSX.utils.sheet_to_html
与XLSX.utils.sheet_to_json
方法将转换后的数据或者dom赋值给全局变量时,由于是在render.onload方法中进行的,因此就引发了this指向的问题,所以需要在外不定义this,以便在render.onload方法中赋值let _this = this;
3.在引入xlsx插件的时候,需要import * as xlsx from 'xlsx'
重命名