首先安装
npm install -save xlsx
关键步骤如下:
1、引入
var XLSX = require("xlsx");
2、html部分
...........
<div>
<input
type="file"
@change="importExcel(this)"
id="imFile"
style="display: none"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
/>
</div>
...........
3、JS部分
........
uploadFile:function(){
// 加 判断
// document.getElementById("imFile").click();
// 点击导入按钮
this.imFile.click();
},
importExcel(file) {
// 导入Excel并解析
this.fullloading = true;
let obj = this.imFile;
if (!obj.files) {
this.fullloading = false;
return;
}
var f = obj.files[0];
const types = f.name.split('.')[1];
// console.log('文件类型 '+types);
const fileType = ['xlsx', 'xlc', 'xlm', 'xls', 'xlt', 'xlw', 'csv'].some(item => item === types);
if (!fileType) {
this.fullloading = false;
this.msg_obj={'showtype':'warning','note':'格式错误!请重新选择'};
return
}
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);
// console.log(json); //这一步已经 把数据取到
$t.dealFile($t.changdata(json)); // 解析导入数据
};
if (this.rABS) {
reader.readAsArrayBuffer(f);
} else {
reader.readAsBinaryString(f);
}
},
........
整体源码
<template>
<div class="my_excelup">
<button @click="uploadFile">打开Excel</button>
<div>
<input
type="file"
@change="importExcel(this)"
id="imFile"
style="display: none"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
/>
</div>
<div class="pre_more">
<span class="pre_excel_up_bg" @click="closeshow"></span>
<div class="pre_excel_up_conten">
<span class="pre_more_close">
<img src="../../assets/image/shan1.png" @click="closeshow" />
</span>
<div class="pre_upload">
<div class="pre_leve_one">
<button class="pre_btn_ok" @click="uploaddata">上传</button>
<button class="pre_btn_ok" @click="cancel_uploaddata">取消</button>
</div>
<div class="pre_leve_two">
<!-- table部分 -->
<div class="pre_tab">
<table class="pre_dataintable">
<thead>
<slot name="tab_excelup_title"></slot>
</thead>
<tbody>
<slot
name="tab_excelup_tr"
v-for="data_tr in show_Data"
:item="data_tr"
></slot>
</tbody>
</table>
</div>
<!-- 分页部分 -->
<div class="pre_page" v-show="show_page">
<ul style="text-align: right; margin-right: 20px;">
<li>
当前页:<label>{{ nowpage }}</label
> 合计页:<label>{{ maxpage }}</label
> <a href="#" @click="firstpage">首页</a>|
<a href="#" @click="beforepage">上一页</a>|
<a href="#" @click="nextpage">下一页</a>|
<a href="#" @click="lastpage">尾页</a>
<input type="text" v-model="jumppage" value="" /><a
href="#"
@click="gopage"
class="go"
>Go</a
>
</li>
</ul>
</div>
</div>
<a id="downlink"></a>
<a id="loodlink" target="_blank"></a>
<!-- 弹出向导层 end-->
</div>
</div>
</div>
<!-- 放置自定义组件 -->
<per-message :message_data="msg_obj" />
<pre-loading :pre_show_loading="fullloading" />
</div>
</template>
<script>
/*
名称:导入Excel
日期:2019-06-06
作者:hj
目标:
1、默认展示一个按钮,
2、上传Excel并检查格式。样式表格通过slot设定。
3、通过则上传数据到数据库,取消则关闭展示界面
4、通过props绑定上传业务类别,以便于后台区分。
*/
// 引入xlsx
var XLSX = require("xlsx");
import { base_encode } from "@/utils/base64.js";
import { GetShort,BackSpecial,DeleteSpecialWord } from "@/utils/localstore.js";
import { BrowserGet } from '@/utils/systemSelect.js';
export default {
name: "pre_excel_up",
components: {
'per-message':()=>import("./pre_message.vue"),
'pre-loading':()=>import("./pre_loading.vue")
},
data() {
return {
fullloading:false,
show_exceldata:false,
imFile: "", // 导入文件el
xlsxJson:'',
errorDialog: false, // 错误信息弹窗
errorMsg: "", // 错误信息内容
excelData:[], // 总的Excel信息
show_Data:[], // 展示Excel信息
show_page:false,
maxpage:'',
nowpage:'',
jumppage:'',
perpage:15,
api_url:'',
post_data:'',
msg_obj:{},
errnum:''
};
},
props: {
/* 指定上级类别 */
pre_uplevel:{ type:Object,default:null },
/* 指定传输类别 */
pre_type:{ type:String,default:'' },
/* 指定角色类别 */
pre_role:{ type:Array,default:null },
/* 指定步骤类别 */
pre_step:{ type:Array,default:null },
},
created:function(){
this.nowpage=1;
this.api_url='/Data_Back';
},
mounted(){
this.imFile = document.getElementById("imFile");
},
methods: {
uploadFile:function(){
// 判断
if(this.pre_type=='business'){
console.log(this.pre_uplevel.id+' '+this.pre_uplevel.name);
if(this.pre_uplevel.id==undefined || this.pre_uplevel.name==undefined){
this.msg_obj={'showtype':'warning','note':'请选择上级业务类别'};
return;
}
}else{
this.msg_obj={'showtype':'warning','note':'没有设置传输Excel 类型'};
return;
}
// document.getElementById("imFile").click();
// 点击导入按钮
this.imFile.click();
},
importExcel(file) {
// 导入Excel并解析
this.fullloading = true;
let obj = this.imFile;
if (!obj.files) {
this.fullloading = false;
return;
}
var f = obj.files[0];
const types = f.name.split('.')[1];
// console.log('文件类型 '+types);
const fileType = ['xlsx', 'xlc', 'xlm', 'xls', 'xlt', 'xlw', 'csv'].some(item => item === types);
if (!fileType) {
this.fullloading = false;
this.msg_obj={'showtype':'warning','note':'格式错误!请重新选择'};
return
}
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);
// console.log(json); //这一步已经 把数据取到
$t.dealFile($t.changdata(json)); // 解析导入数据
};
if (this.rABS) {
reader.readAsArrayBuffer(f);
} else {
reader.readAsBinaryString(f);
}
},
dealFile: function(data) {
// 处理导入的数据
this.imFile.value = "";
this.fullloading = false;
if (data.length <= 0) {
this.msg_obj={'showtype':'warning','note':'导入数据长度为0,请检查'};
} else {
this.excelData = data;
this.loaddata();
}
},
changdata:function(data){
// 转换到指定格式
this.errnum=0;
// console.log(this.pre_role);
// console.log(this.pre_step);
if(this.pre_type=='business'){
// console.log('开始转换');
var temp_data=[];
for(var i=0;i<data.length;i++){
var to={};
to.upid=this.pre_uplevel.id;
to.upname=this.pre_uplevel.name
to.name=data[i].name;
var t_role={};
t_role=this.checkrole(data[i].role);
to.role_id=t_role.id;
to.role=t_role.name;
var t_type={};
t_type=this.checktype(data[i].type);
to.type_id=t_type.id;
to.type=t_type.name;
to.days=data[i].days;
// console.log(to);
temp_data[i]=to;
}
data=[];
data=temp_data;
}
return data;
},
checkrole:function(role){
// 检查类型1
var o={};
var t=false;
for(var j=0;j<this.pre_role.length;j++){
if(this.pre_role[j].val==role){
o.id=this.pre_role[j].id;
t=true;
break;
}
}
if(t){
o.name=role;
}else{
o.name='[格式错误]'+role;
this.errnum+=1;
}
return o;
},
checktype:function(parm){
// 检查类型2
var o={};
var t=false;
for(var j=0;j<this.pre_step.length;j++){
if(this.pre_step[j].val==parm){
o.id=this.pre_step[j].id;
t=true;
break;
}
}
if(t){
o.name=parm;
}else{
o.name='[格式错误]'+parm;
this.errnum+=1;
}
return o;
},
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;
},
importExcel2(file) {
// console.log('导入');
// console.log(file);
var file_exp=document.getElementById("imFile");
file = document.getElementById("imFile").files[0]; // 使用传统的input方法需要加上这一步
const types = file.name.split('.')[1];
const fileType = ['xlsx', 'xlc', 'xlm', 'xls', 'xlt', 'xlw', 'csv'].some(item => item === types);
if (!fileType) {
alert('格式错误!请重新选择')
return
}
this.fullscreenLoading=true;
this.file2Xce(file).then(tabJson => {
if (tabJson && tabJson.length > 0) {
this.xlsxJson = tabJson;
console.log(tabJson);
// console.log(this.xlsxJson[0].sheet);
// console.log(JSON.stringify(this.xlsxJson[0].sheet));
// this.filedata=JSON.stringify(this.xlsxJson[0].sheet);
// this.savefile();
var data=[];
for(var i=0;i<tabJson.length;i++){
var obj={};
obj.sheet=tabJson[i].sheet;
obj.sheetName=tabJson[i].sheetName;
data[i]=obj;
}
this.filedata=JSON.stringify(data);
// xlsxJson就是解析出来的json数据,数据格式如下
// [
// {
// sheetName: sheet1
// sheet: sheetData
// }
// ]
}
})
},
file2Xce(file) {
// 传统方式上传
return new Promise(function(resolve, reject) {
const reader = new FileReader()
reader.onload = function(e) {
const data = e.target.result
this.wb = XLSX.read(data, {
type: 'binary'
})
const result = []
this.wb.SheetNames.forEach((sheetName) => {
result.push({
sheetName: sheetName,
sheet: XLSX.utils.sheet_to_json(this.wb.Sheets[sheetName])
})
})
resolve(result)
}
// reader.readAsBinaryString(file.raw)
reader.readAsBinaryString(file) // 传统input方法
})
},
openshow:function(){
// console.log('状态改变 == '+this.show_filedown);
var Hg = $(document).height();
// 设置背景高度
$(".pre_excel_up_bg").height(Hg);
// 设置展示动画 第一次有慢入动作,第二次没有:原因是当前页面被缓存,除非重开
$(".pre_excel_up_bg").fadeIn("3000");
$(".pre_excel_up_conten").fadeIn("3000");
},
closeshow:function(){
$(".pre_excel_up_bg").fadeOut("3000");
$(".pre_excel_up_conten").fadeOut("3000");
},
firstpage:function(){
if(Number(this.nowpage)>1){
this.nowpage=1;
this.loaddata();
}else{
this.msg_obj={'showtype':'warning','note':'已经是第一页'};
}
},
beforepage:function(){
if(Number(this.nowpage)>1){
this.nowpage--;
this.loaddata();
}else{
this.msg_obj={'showtype':'warning','note':'已经是第一页'};
}
},
nextpage:function(){
if(Number(this.nowpage)<Number(this.maxpage)){
this.nowpage++;
this.loaddata();
}else{
this.msg_obj={'showtype':'warning','note':'已经是最后一页'};
}
},
lastpage:function(){
if(Number(this.nowpage)<Number(this.maxpage)){
this.nowpage=this.maxpage;
this.loaddata();
}else{
this.msg_obj={'showtype':'warning','note':'已经是最后一页'};
}
},
gopage:function(){
console.log('跳转到='+this.jumppage);
if(Number(this.jumppage)>0 && Number(this.jumppage)<=Number(this.maxpage)){
this.nowpage=this.jumppage;
this.loaddata();
}else{
this.msg_obj={'showtype':'warning','note':'跳转页数不在规定范围内,请检查'+this.jumppage};
}
},
loaddata:function(){
this.openshow();
if(this.excelData.length>this.perpage){
this.show_page=true;
}else{
this.show_page=false;
}
this.show_Data=[];
var j=0
for(var i=0;i<this.excelData.length;i++){
if(i>=((this.nowpage-1)*this.perpage)&&i<(this.nowpage*this.perpage-1)){
this.show_Data[j]=this.excelData[i];
j++;
}
}
console.log(this.show_Data);
},
uploaddata:function(){
console.log('上传检查');
if (this.errnum > 0) {
this.msg_obj={'showtype':'warning','note':'发现格式错误'+this.errnum+'处,请检查'};
return;
}
console.log('上传通过');
this.post_data='';
if(this.pre_type=='business'){
var tdata='[';
for(var i=0;i<this.excelData.length;i++){
tdata +=
'{"name":"'+DeleteSpecialWord(this.excelData[i].name)+
'","upid":"' +DeleteSpecialWord(this.excelData[i].upid) +
'","rid":"' +DeleteSpecialWord(this.excelData[i].role_id) +
'","tid":"' +DeleteSpecialWord(this.excelData[i].type_id) +
'","day":"' +DeleteSpecialWord(this.excelData[i].days) +'"},';
}
tdata=tdata.substring(0,(tdata.length-1));
tdata+=']'
this.post_data ='{"method":"Excel_Data","data":"' + base_encode(tdata) + '"}';
}
this.neworupdate();
},
cancel_uploaddata:function(){
console.log('取消上传');
this.excelData=[];
this.pre_step=[];
this.pre_role=[];
this.post_data='';
this.closeshow();
},
neworupdate:function() {
// console.log(this.api_url);
// console.log(this.pre_post_upd);
if (this.post_data =='') {
this.msg_obj={'showtype':'warning','note':'上传数据为空,请检查'};
return;
}
this.fullloading=true;
this.$post(
this.api_url,
this.post_data,
).then(res => {
this.fullloading=false;
try {
console.log(res);
res=JSON.parse(res);
console.log(res.data);
if (res.status == 1) {
this.msg_obj={'showtype':'ok','note':res.msg};
// this.loaddata();
this.RefreshData();
this.closeshow();
} else {
this.msg_obj={'showtype':'err','note':res.msg};
}
// this.initTable();
} catch (ex) {
this.msg_obj={'showtype':'warning','note':"查询失败"+ex};
}
});
},
RefreshData:function(){
console.log(this.pre_uplevel);
var t='';
for(var i=0;i<(Math.random()*10);i++){
t+=' '
}
this.$emit("my-excel",'',this.pre_uplevel.name+t,this.pre_uplevel);
}
}
};
</script>
<style scoped>
.my_excelup {
display: inline-block;
margin-left: 10px;
}
.pre_excel_up_bg {
width: 100%;
background: #000000;
opacity: 0.5;
position: fixed;
top: 0;
left: 0;
height: 1340px;
display: none;
z-index: 99;
}
.pre_more {
position: absolute;
top: 0;
left: 0;
width: 100%;
}
.pre_excel_up_conten {
width: 70%;
height: auto;
margin: 0 auto;
background: #faf5f5;
position: fixed;
top: 20%;
border-radius: 3px;
display: none;
z-index: 999;
/* left: 40%; */
left: 15%;
/* text-align: center; */
}
.pre_more_close {
position: absolute !important;
right: -8px !important;
top: -6px !important;
font-size: 30px !important;
color: #b4b4b4;
cursor: pointer;
font-weight: normal;
}
.pre_excel_up_conten > div {
/* margin-top: 15px; */
width: 100%;
text-align: center;
padding-left: 5px;
padding-right: 5px;
}
.pre_excel_up_conten > div > * {
/* display: inline-block; */
border-radius: 5px;
/* line-height: 15px; */
}
.pre_excel_up_conten > div > span {
width: 100px;
/* margin-left: -40px; */
text-align: right;
}
.pre_excel_up_conten > div > input {
width: 168px;
margin-right: 32px;
}
.pre_excel_up_conten > div > button {
/* margin-left: 20%; */
background-color: rgba(68, 70, 238, 0.986);
color: white;
font-optical-sizing: 16px;
cursor: pointer;
}
.pre_upload {
width: 100%;
min-height: 200px;
height: 100%;
background-color: azure;
text-align: center;
/* padding: 10px 20px 10px 20px; */
}
.pre_leve_one {
height: 25px;
text-align: left;
padding-top: 18px;
padding-left: 15px;
}
.pre_leve_one > button {
margin-left: 10px;
border-radius: 2px;
background-color: #fff;
color: #000000;
padding: 2px 10px 2px 10px;
}
.pre_leve_two {
/* padding: 5px; */
margin: 15px;
margin-top: 15px;
border: 1px solid #191970;
min-height: 200px;
height: auto;
}
.pre_dataintable {
margin-top: 15px;
border-collapse: collapse;
border: 1px solid #aaa;
width: 95%;
/* padding 没有作用 */
/* padding: 0px 5px 10px 5px; */
position: relative;
left: 2%;
}
.pre_dataintable th {
vertical-align: baseline;
padding: 5px 15px 5px 6px;
background-color: rgb(87, 201, 230);
border: 1px solid #3f3f3f;
text-align: left;
color: #000000;
font-size: 16px;
font-weight: bolder;
}
.pre_dataintable td {
/* vertical-align: center; */
text-align: left;
padding: 6px 15px 6px 6px;
border: 1px solid #aaa;
}
.pre_dataintable tr:nth-child(odd) {
background-color: #f5f5f5;
}
.pre_dataintable tr:nth-child(even) {
background-color: #fff;
}
.pre_tab_name {
cursor: pointer;
width: 100px;
text-align: left;
/* white-space: nowrap; */
word-break: break-all;
overflow: hidden;
/* text-overflow: ellipsis; */
/* display: -webkit-box; */
/* -webkit-line-clamp: auto; */
/* -webkit-box-orient: vertical; */
}
.pre_tab_name:hover {
cursor: pointer;
background-color: #aaa;
}
.td_btn {
text-align: center !important;
}
.td_btn > button {
border-radius: 3px;
width: 100px;
height: 28px;
padding: 1px 2px 2px 2px;
}
.td_btn > button:hover {
background-color: rgba(155, 222, 231, 0.986);
cursor: pointer;
}
/* 翻页样式 */
.pre_block {
width: 100%;
margin-top: 5px;
margin-bottom: 5px;
}
.pre_block > ul {
text-align: right;
list-style: none;
}
.pre_block > ul > li > a {
text-decoration: none;
}
.pre_block > ul > li > .go {
display: inline-block;
width: 40px;
height: 20px;
border: 1px solid #cccccc;
background: #024aee;
color: #fff;
border-radius: 4px;
text-align: center;
margin-left: 5px;
}
.pre_block > ul > li > a:hover {
color: #394656;
}
.pre_btn_ok {
background: rgba(68, 70, 238, 0.986);
color: white;
font-optical-sizing: 16px;
cursor: pointer;
}
.pre_btn_ok:hover {
background: rgba(161, 161, 192, 0.986);
}
</style>