特性:
- 支持批量上传文件、文件夹
- 可自定义headers
- 可自定义过滤上传格式
- 可自定义上传API接口
- 支持drag属性开启可拖拽上传文件、文件夹
sgUpload源码
<template>
<div :class="$options.name" :dragenter="isDragenter">
<!-- 上传按钮_________________________________________________________ -->
<!-- 上传文件 -->
<el-upload ref="uploadFile" :show-file-list="false" :headers="headers" :accept="accept.toString()"
:action="actionUrl" :before-upload="beforeUpload" :on-success="uploadSuccess" :on-error="uploadError">
</el-upload>
<!-- 上传文件夹 -->
<el-upload ref="uploadFolder" :show-file-list="false" :headers="headers" :action="actionUrl"
:before-upload="beforeUpload" :on-success="uploadSuccess" :on-error="uploadError" :on-exceed="exceed" multiple
:drag="drag === '' || drag">
</el-upload>
<!-- _________________________________________________________ -->
<!-- 上传托盘(右下角) -->
<sgUploadTray v-model="showUploadTray" :data="uploadList" @stopUpload="stopUpload"
@dragStart="disabledRectSelect = true" @dragEnd="disabledRectSelect = false"
v-if="!(hideUploadTray === '' || hideUploadTray)" />
</div>
</template>
<script>
import sgUploadTray from "@/vue/components/admin/sgUploadTray";
export default {
name: 'sgUpload',
components: { sgUploadTray },
data() {
return {
// 上传----------------------------------------
headers: { kkToken: localStorage.token, }, //获取token(注意仔细看后端接受token的字段名是不是叫做“token”)
accept: `.${['png', 'jpg', 'jpeg', 'bmp', 'gif', 'svg'].join(',.')}`,//默认只支持图片格式上传
actionUrl: `${this.$d.API_ROOT_URL}/customer/importCustomerData`,
dur: 100,
percent: 100,
uploadList: [],
showUploadTray: false,
uploadFileBtn: null,//上传文件
uploadFolderBtn: null,//上传文件夹
isDragenter: false,//是否拖入
leaveEvents: [
'mouseenter',
'mouseover',
'mousemove',
'mouseout',
'blur',
'visibilitychange',
],
dragAreaDom: null,//拖拽放入区域
isDragTrigger: false,//是否为拖拽触发上传
// ----------------------------------------
}
},
props: [
"data", //上传可选参数
"hideUploadTray",//不显示上传托盘
"drag",//是否支持拖拽文件、文件夹或多个文件
],
watch: {
data: {
handler(d) {
if (d) {
d.headers && (this.headers = d.headers);
d.accept && (this.accept = d.accept);
d.actionUrl && (this.actionUrl = d.actionUrl);
}
}, deep: true, immediate: true,
},
drag: {
handler(d) {
if (d === '' || d) {
this.addEvents();
} else {
this.removeEvents();
}
}, deep: true, immediate: true,
},
},
mounted() {
this.$nextTick(() => {
this.uploadFileBtn = this.$refs.uploadFile.$children[0].$refs.input;
this.uploadFolderBtn = this.$refs.uploadFolder.$children[0].$refs.input;
this.uploadFolderBtn && (this.uploadFolderBtn.webkitdirectory = true);//让el-upload支持上传文件夹
this.dragAreaDom = this.$refs.uploadFolder.$el.querySelector(`.el-upload-dragger`);
this.dragAreaDom && this.dragAreaDom.addEventListener('drop', this.drop);
})
},
destroyed() {
this.removeEvents();
},
methods: {
// 监听----------------------------------------
addEvents(d) {
this.removeEvents();
addEventListener('dragenter', this.dragenter);
this.leaveEvents.forEach(v => addEventListener(v, this.leave));
this.dragAreaDom && this.dragAreaDom.addEventListener('drop', this.drop);
},
removeEvents(d) {
removeEventListener('dragenter', this.dragenter);
this.leaveEvents.forEach(v => removeEventListener(v, this.leave));
this.dragAreaDom && this.dragAreaDom.removeEventListener('drop', this.drop);
},
dragenter(d) {
this.isDragTrigger = true;
this.isDragenter = true;
},
leave(d) {
this.isDragenter = false;
},
drop(d) {
// 触发拖拽上传
this.uploadDragFiles(d, file => {
file.isDragFile = true;
this.beforeUpload(file)
}, files => {
});
},
// 循环获取拖拽过来的file----------------------------------------
uploadDragFiles(e, uploadFunc, completeFunc) {
let files = [], items = [].slice.call(e.dataTransfer.items);
items.forEach((v, i) => {
const webkitGetAsEntry = v.webkitGetAsEntry();
eval(webkitGetAsEntry.isDirectory ? 'setfolder' : 'setfile')(webkitGetAsEntry);
});
// 处理文件夹
function setfolder(webkitGetAsEntry) {
webkitGetAsEntry.createReader().readEntries(entries => (entries.forEach(item => (item.isFile ? setfile(item) : setfolder(item)))));
}
// 处理文件
function setfile(webkitGetAsEntry) {
webkitGetAsEntry.file(file => {
uploadFunc && uploadFunc(file);
files.push(file);
});
}
completeFunc && completeFunc(files);
},
// 上传按钮触发----------------------------------------
triggerUploadFile(d) {
this.isDragTrigger = false;
this.uploadFileBtn && this.uploadFileBtn.click();
},
triggerUploadFolder(d) {
this.isDragTrigger = false;
this.uploadFolderBtn && this.uploadFolderBtn.click();
},
// 上传文件----------------------------------------------------------------
showFakeLoading(file) {
file.raw && (file = file.raw);
file = this.uploadList.find(v => v.uid == file.uid);
clearInterval(file.interval);
file.percent = 0;
file.interval = setInterval(() => {
file.percent >= 99 ? this.hideFakeLoading(file) : file.percent++;
}, this.dur);
},
hideFakeLoading(file, { type, tip, color } = {}) {
file.raw && (file = file.raw);
file = this.uploadList.find(v => v.uid == file.uid);
clearInterval(file.interval);
switch (type) {
case 'error':
file.percent = 0;
break;
case 'success':
default:
file.percent = 100;
}
type && (file.type = type);
tip && (file.tip = tip);
color && (file.color = color);
},
exceed(file, fileList) {
this.$message.error("上传文件数量太大,分散上传吧!");
},
stopUpload(d) {
this.$refs.uploadFolder.abort();
//console.log(`取消上传`, d);
},
//文件上传之前
beforeUpload(file) {
if ((this.drag === '' || this.drag) && this.isDragTrigger) {
if (!file.isDragFile) return;//拖拽模式下,如果不是原生js捕获到的拖拽文件,就不进入上传队列
}
file.uid || (file.uid = this.$g.UUID());
this.uploadList.unshift({
interval: null,
uid: file.uid,
percent: 0,//加载进度
name: file.name,
size: file.size,
type: file.type,
webkitRelativePath: file.webkitRelativePath,
type: '',
tip: '',
color: '',
});
this.showUploadTray = true;
// 判断是不是特定的格式________________________
let isFile = this.accept === '*' ? true : this.accept.includes(file.name.toLocaleLowerCase().split(".").pop());
const maxSize = 50; //限制大小
const isAllowSize = file.size / 1024 / 1024 <= maxSize;
isFile || this.$message.error("上传文件只能是" + this.accept + "格式");
isAllowSize || this.$message.error("上传文件大小不能超过" + maxSize + "MB");
let allowUpload = isFile && isAllowSize;
if (allowUpload) {
this.showFakeLoading(file);
this.$g.file2Base64Image(file, d => this.$emit(`resultBase64Image`, d));
this.$emit(`beforeUpload`, file);
} else {
this.hideFakeLoading(file, { type: 'error', tip: "上传失败", color: "red" });
}
return allowUpload; //若返回false则停止上传
},
//上传成功
uploadSuccess(response, file, fileList) {
if ((this.drag === '' || this.drag) && this.isDragTrigger) {
if (!file.isDragFile) return;//拖拽模式下,如果不是原生js捕获到的拖拽文件,就不进入上传队列
}
if (response.data && response.data.key) {
// 下载失败原因的描述文件
this.$d.customer_downloadImportCustomerExcel({ key: response.data.key }, {
s: (d) => {
this.$emit(`error`, response, file);
this.hideFakeLoading(file, { type: 'error', tip: "上传失败", color: "red" });
this.$g.downloadFile(d, `${file.name}-上传失败原因`, '.xls');
this.$message.error(`${file.name}-上传失败,请查看失败原因`);
// this.initList();//刷新列表
//console.log('上传失败', response, file, fileList);
}
});
} else if (response.success) {
this.$emit(`success`, response, file);
// 上传成功了
this.hideFakeLoading(file, { type: 'success', tip: "上传成功", color: "green" });
this.$message.success(`“${file.name}上传成功`);
// this.initList();//刷新列表
//console.log('上传成功', response, file, fileList);
} else {
this.$emit(`error`, response, file);
// 其他失败原因
this.hideFakeLoading(file, { type: 'error', tip: "上传失败", color: "red" });
// this.$message.error(response.msg);
//console.log('上传失败', response, file, fileList);
}
},
//上传失败
uploadError(err, file, fileList) {
if ((this.drag === '' || this.drag) && this.isDragTrigger) {
if (!file.isDragFile) return;//拖拽模式下,如果不是原生js捕获到的拖拽文件,就不进入上传队列
}
this.$emit(`error`, err, file);
this.hideFakeLoading(file, { type: 'error', tip: "上传失败", color: "red" });
this.$message.error("上传失败");
//console.log('上传失败', err, file, fileList);
},
}
};
</script>
<style lang="scss">
.sgUpload {
width: 0;
height: 0;
.el-upload-dragger {
z-index: 999999; //根据情况自己拿捏
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
display: none;
background-color: #ffffff99;
&::after {
content: "拖拽文件到此处";
position: absolute;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
color: #743a72;
font-size: 18px;
font-weight: bold;
line-height: 1.2;
}
}
&[dragenter] .el-upload-dragger {
display: block;
border-color: #743a72;
&.is-dragover {
background-color: #743a7222;
&::after {
content: "松掉鼠标上传文件";
}
}
}
}
</style>
应用
<template>
<div>
<div style="width:300px;height:300px;position: relative;">
<img :src="src" style="width:100%;height:100%">
<!-- 上传组件 -->
<sgUpload drag ref="sgUpload" :data="{
accept: `*`,
actionUrl: `${$d.API_ROOT_URL}/customer/importCustomerData`,
}" @resultBase64Image="resultBase64Image" @success="uploadSuccess" @error="uploadError" hideUploadTray />
</div>
<el-button type="primary" icon="el-icon-upload2" @click="d => $refs.sgUpload.triggerUploadFile()">上传</el-button>
</div>
</template>
<script>
import sgUpload from "@/vue/components/admin/sgUpload";
export default {
components: {
sgUpload,
},
data() {
return {
src: '',
}
},
methods: {
resultBase64Image(d, f) {
console.log(this.$options.name)
this.src = d;
},
uploadSuccess(d, f) { }, uploadError(d, f) { },
}
};
</script>