粘贴、拖拽、点击上传组件(vue2)
效果图
- 未上传

- 上传中

- 展示等

代码
<template>
<div
class="copy-box"
v-loading="fileLoading"
:disabled="type == 'detail'"
:element-loading-text="remove ? '删除中' : '上传中'"
>
<div
id="preview"
ref="drop-box"
v-if="type != 'detail'"
@dragover="fileDragover"
@drop="dropEvent"
v-on:paste="handlePaste"
>
<p>
将文件粘贴、拖拽到此处或<el-button
type="text"
class="upload-btn"
@click="$refs.evfile.click()"
>点击上传</el-button
>
</p>
<input
type="file"
ref="evfile"
multiple
@change="uploadFile"
style="display: none"
/>
</div>
<div class="demo-image__preview" v-if="fileList.length > 0">
<div
class="img-list"
v-for="(item, index) in fileList"
:key="index + 1"
@mouseover="imgNum = index + 1"
@mouseout="imgNum = 0"
>
<div
v-show="imgNum == index + 1 && type != 'detail'"
class="img-remove"
@click="handleImgRemove(index, fileList)"
>
×
</div>
<el-image
style="width: 100%; height: 100%"
:src="item"
fit="cover"
:preview-src-list="fileList"
>
</el-image>
</div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue, Prop, Watch } from "vue-property-decorator";
import { Image } from "element-ui";
import { uploadBatchFile, deleteFile } from "@/api/task";
@Component({
components: {
[Image.name]: Image,
},
})
export default class UploadImg extends Vue {
public $refs!: {
[propName: string]: any;
};
@Prop({ type: Number, default: 5 }) maxSize;
@Prop({ type: String, default: "edit" }) type;
@Prop({ type: String, default: "" }) data;
@Watch("data", { deep: true, immediate: true })
handleWatchData(val) {
console.log(val);
if (val && val.length) {
this.fileList = val.split(",");
}
}
fileLoading = false;
private fileList = [];
private imgNum = 0;
private remove = false;
private verifyFun(list: any) {
if (list.length == 0) return false;
let that = this;
for (let i = 0; i < list.length; i++) {
if (list[i].type.indexOf("image") == -1) {
that.$message("请选择图片上传");
return false;
}
if (list[i].size >= 10485760) {
that.$message("请上传小于10M的文件");
return false;
}
}
if (!that.verifyLength(list.length)) {
that.$message(`所选超过${that.maxSize}张`);
return false;
}
return true;
}
private verifyLength(list) {
if (this.fileList.length + list > this.maxSize) {
return false;
} else if (this.fileList.length + list <= this.maxSize) {
return true;
}
}
private handlePaste($event) {
console.log($event);
const items = ($event.clipboardData || (window as any).clipboardData).items;
let file = [];
if (!items || items.length === 0) {
this.$message.error("当前浏览器不支持本地");
return;
}
if (!this.verifyFun(items)) {
return false;
}
for (let i = 0; i < items.length; i++) {
let f = items[i].getAsFile();
const type = f.type.split("/");
const renameFile = new File([f], new Date().getTime() + "." + type[1], {
type: f.type,
});
file.push(renameFile);
}
this.updata(file);
}
private uploadFile(evfile) {
let file = evfile.target.files;
if (!this.verifyFun(file)) {
return false;
} else {
this.updata(file);
}
}
private dropEvent(e) {
e.preventDefault();
console.log(e.dataTransfer.files, e.dataTransfer.files.length);
const file = e.dataTransfer.files;
if (!this.verifyFun(file)) {
return false;
} else {
this.updata(file);
}
}
private updata(fileList: any) {
console.log(fileList);
this.fileLoading = true;
let formData = new FormData();
for (let x = 0; x < fileList.length; x++) {
formData.append("file", fileList[x]);
}
this.upLoadFun(formData)
.then((res) => {
this.$message.success("上传成功");
this.$emit("successFile", this.fileList.join(","));
this.$refs.evfile.value = "";
this.fileLoading = false;
})
.catch((e) => {
this.$emit("errorFile", e);
this.fileLoading = false;
});
}
private upLoadFun(file) {
return new Promise((res, rej) => {
uploadBatchFile(file)
.then(({ data }) => {
let d = this.fileList.concat(data);
this.$set(this, "fileList", d);
res(data);
})
.catch((e) => {
rej(e);
});
});
}
handleImgRemove(index, file) {
this.remove = true;
this.fileLoading = true;
console.log(index, file);
deleteFile(file[index])
.then((res) => {
file.splice(index, 1);
this.fileLoading = false;
this.remove = false;
this.$emit("successFile", file.join(","));
})
.catch(() => {
this.fileLoading = false;
this.remove = false;
});
}
fileDragover(e) {
e.preventDefault();
}
}
</script>
<style lang="scss" scoped>
.copy-box {
width: 100%;
text-align: center;
display: flex;
flex-direction: column;
max-height: 300px;
min-height: 0;
overflow-y: auto;
#preview {
min-height: 150px;
display: flex;
align-items: center;
justify-content: center;
color: #409eff;
font-size: 16px;
border: 1px dashed #d9d9d9;
border-radius: 5px;
color: #606266;
font-weight: 200;
font-size: 14px;
}
#preview:hover {
border-color: #409eff;
}
.demo-image__preview {
text-align: left;
padding-top: 5px;
.img-list {
width: 100px;
height: 100px;
display: inline-block;
margin-left: 10px;
overflow: hidden;
position: relative;
}
.img-list:first-child {
margin-left: 0;
}
.img-list:nth-child(4n + 1) {
margin-left: 0;
}
}
.img-remove {
background-color: rgba(0, 0, 0, 0.6);
color: #fff;
position: absolute;
right: 0;
top: 0;
cursor: pointer;
width: 20px;
height: 20px;
border-bottom-left-radius: 5px;
text-align: center;
line-height: 18px;
z-index: 10;
}
.upload-demo {
flex-shrink: 0;
}
}
</style>
备注
- 给组件外套个盒子调整内容
- 里面的代码看自己需求修改
- 里面用到了element的Image组件 所以需要注册一下 全局的话 删了就行
- 别喷我写的不好,喷就你对 -_- 。