您的位置:首页 > Web前端 > Vue.js

vue前端实现导入导出excel(兼容IE11)

2018-07-13 16:08 826 查看

前端vue实现excel的导入导出

首先说明,大部分代码引自:纯前端实现excel表格上传下载

主要代码

<template>
<div class="index" v-loading.fullscreen.lock="fullscreenLoading" element-loading-text="拼命加载中...">
<input type="file" @change="importFile(this)" id="imFile" style="display: none"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"/>
<a id="downlink"></a>
<el-button class="button" @click="uploadFile()">导入</el-button>
<el-button class="button" @click="downloadFile(excelData)">导出</el-button>
<!--错误信息提示-->
<el-dialog title="提示" v-model="errorDialog" size="tiny">
<span>{{errorMsg}}</span>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="errorDialog=false">确认</el-button>
</span>
</el-dialog>
<!--展示导入信息-->
<el-table :data="excelData" tooltip-effect="dark">
<el-table-column label="名称" prop="name" show-overflow-tooltip></el-table-column>
<el-table-column label="分量" prop="size" show-overflow-tooltip></el-table-column>
<el-table-column label="口味" prop="taste" show-overflow-tooltip></el-table-column>
<el-table-column label="单价(元)" prop="price" show-overflow-tooltip></el-table-column>
<el-table-column label="剩余(份)" prop="remain" show-overflow-tooltip></el-table-column>
</el-table>
</div>
</template>

<script>
var XLSX = require('xlsx')
export default {
name: 'Index',
data () {
return {
fullscreenLoading: false, // 加载中
imFile: '', // 导入文件el
outFile: '',  // 导出文件el
errorDialog: false, // 错误信息弹窗
errorMsg: '', // 错误信息内容
excelData: [  // 测试数据
{
name: '红烧鱼', size: '大', taste: '微辣', price: '40', remain: '100'
},
{
name: '麻辣小龙虾', size: '大', taste: '麻辣', price: '138', remain: '200'
},
{
name: '清蒸小龙虾', size: '大', taste: '清淡', price: '138', remain: '200'
},
{
name: '香辣小龙虾', size: '大', taste: '特辣', price: '138', remain: '200'
},
{
name: '十三香小龙虾', size: '大', taste: '中辣', price: '138', remain: '108'
},
{
name: '蒜蓉小龙虾', size: '大', taste: '中辣', price: '138', remain: '100'
},
{
name: '凉拌牛肉', size: '中', taste: '中辣', price: '48', remain: '60'
},
{
name: '虾仁寿司', size: '大', taste: '清淡', price: '29', remain: '无限'
},
{
name: '海苔寿司', size: '大', taste: '微辣', price: '26', remain: '无限'
},
{
name: '金针菇寿司', size: '大', taste: '清淡', price: '23', remain: '无限'
},
{
name: '泡菜寿司', size: '大', taste: '微辣', price: '24', remain: '无限'
},
{
name: '鳗鱼寿司', size: '大', taste: '清淡', price: '28', remain: '无限'
},
{
name: '肉松寿司', size: '大', taste: '清淡', price: '22', remain: '无限'
},
{
name: '三文鱼寿司', size: '大', taste: '清淡', price: '30', remain: '无限'
},
{
name: '蛋黄寿司', size: '大', taste: '清淡', price: '20', remain: '无限'
}
]
}
},
mounted () {
this.imFile = document.getElementById('imFile')
this.outFile = document.getElementById('downlink')
},
methods: {
uploadFile: function () { // 按钮导入
this.imFile.click()
},
downloadFile: function (rs) { // 按钮导出
let data = [{}]
for (let k in rs[0]) {
data[0][k] = k
}
data = data.concat(rs)
this.downloadExl(data, '菜单')
},
importFile: function () { // 导入excel
this.fullscreenLoading = true
let obj = this.imFile
if (!obj.files) {
this.fullscreenLoading = false
return
}
var f = obj.files[0]
var reader = new FileReader()
let $t = this
reader.onload = function (e) {
var data = e.target.result
if ($t.rABS) {
$t.wb = XLSX.read(btoa(this.fixdata(data)), {  // 手动转化
type: 'base64'
})
} else {
$t.wb = XLSX.read(data, {
type: 'binary'
})
}
let json = XLSX.utils.sheet_to_json($t.wb.Sheets[$t.wb.SheetNames[0]])
console.log(typeof json)
$t.dealFile($t.analyzeData(json)) // analyzeData: 解析导入数据
}
if (this.rABS) {
reader.readAsArrayBuffer(f)
} else {
reader.readAsBinaryString(f)
}
},
downloadExl: function (json, downName, type) {  // 导出到excel
let keyMap = [] // 获取键
for (let k in json[0]) {
keyMap.push(k)
}
console.info('keyMap', keyMap, json)
let tmpdata = [] // 用来保存转换好的json
json.map((v, i) => keyMap.map((k, j) => Object.assign({}, {
v: v[k],
position: (j > 25 ? this.getCharCol(j) : String.fromCharCode(65 + j)) + (i + 1)
}))).reduce((prev, next) => prev.concat(next)).forEach(function (v) {
tmpdata[v.position] = {
v: v.v
}
})
let outputPos = Object.keys(tmpdata)  // 设置区域,比如表格从A1到D10
let tmpWB = {
SheetNames: ['mySheet'], // 保存的表标题
Sheets: {
'mySheet': Object.assign({},
tmpdata, // 内容
{
'!ref': outputPos[0] + ':' + outputPos[outputPos.length - 1] // 设置填充区域
})
}
}
let tmpDown = new Blob([this.s2ab(XLSX.write(tmpWB,
{bookType: (type === undefined ? 'xlsx' : type), bookSST: false, type: 'binary'} // 这里的数据是用来定义导出的格式类型
))], {
type: ''
})  // 创建二进制对象写入转换好的字节流
var href = URL.createObjectURL(tmpDown)  // 创建对象超链接
this.outFile.download = downName + '.xlsx'  // 下载名称
this.outFile.href = href  // 绑定a标签
this.outFile.click()  // 模拟点击实现下载
setTimeout(function () {  // 延时释放
URL.revokeObjectURL(tmpDown) // 用URL.revokeObjectURL()来释放这个object URL
}, 100)
},
analyzeData: function (data) {  // 此处可以解析导入数据
return data
},
dealFile: function (data) {   // 处理导入的数据
console.log(data)
this.imFile.value = ''
this.fullscreenLoading = false
if (data.length <= 0) {
this.errorDialog = true
this.errorMsg = '请导入正确信息'
} else {
this.excelData = data
}
},
s2ab: function (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
},
getCharCol: function (n) { // 将指定的自然数转换为26进制表示。映射关系:[0-25] -> [A-Z]。
let s = ''
let m = 0
while (n > 0) {
m = n % 26 + 1
s = String.fromCharCode(m + 64) + s
n = (n - m) / 26
}
return s
},
fixdata: function (data) {  // 文件流转BinaryString
var o = ''
var l = 0
var w = 10240
for (; l < data.byteLength / w; ++l) {
o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)))
}
o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)))
return o
}
}
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
.el-table th>.cell {
text-align: center;
}
.button {
margin-bottom: 20px;
}
</style>

待处理问题

IE11导入无法实现

解决问题

参考内容:vue中使用excel导入导出

代码主要修改内容

//修改importFile方法即可
importFile(obj) {
let _this = this;
// 通过DOM取文件数据
this.file = event.currentTarget.files[0];
var rABS = false; //是否将文件读取为二进制字符串
var f = this.file;
var reader = new FileReader();
//if (!FileReader.prototype.readAsBinaryString) {
FileReader.prototype.readAsBinaryString = function(f) {
var binary = "";
var rABS = false; //是否将文件读取为二进制字符串
var wb; //读取完成的数据
var outdata;
var reader = new FileReader();
reader.onload = function(e) {
var bytes = new Uint8Array(reader.result);
var length = bytes.byteLength;
for(var i = 0; i < length; i++) {
binary += String.fromCharCode(bytes[i]);
}
var XLSX = require('xlsx');
if(rABS) {
wb = XLSX.read(btoa(fixdata(binary)), { //手动转化
type: 'base64'
});
} else {
wb = XLSX.read(binary, {
type: 'binary'
});
}
outdata = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
//outdata就是你想要的东西
this.da = [...outdata]
let arr = []
this.da.map(v => {
let obj = {}
obj.size = v.size
obj.name = v.name
arr.push(obj)
})
console.log(arr)
let para = {
//withList: JSON.stringify(this.da)
withList: arr
}
}
reader.readAsArrayBuffer(f);
}
if(rABS) {
reader.readAsArrayBuffer(f);
} else {
reader.readAsBinaryString(f);
}
},


温馨提示:处理数据如果过大,可将数据发送到后端使用服务器资源处理。

赶紧试试吧

如果不错,记得点赞哈
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  XLSX Vue.js RABS Prototype