在 web 应用中,文件上传已经成为了一个必不可少的功能。本文将介绍如何使用 vue 和 element 实现简单而强大的文件上传功能,让你的 web 应用更加出色!
其实基于 element
已经封装好的内容,通过 el-upload
组件的属性,实现上传的操作还是很易如拾芥的。我们只需要请求接口上传图片,上传成功后,将后台返回的 url
回显到页面即可。
传递参数
返回数据
用到的属性
属性 | 描述 |
---|---|
accept | 接受上传的文件类型(thumbnail-mode 模式下此参数无效) |
action | 必选参数,上传的地址 |
http-request | 覆盖默认的上传行为,可以自定义上传的实现 |
show-file-list | 是否显示已上传文件列表 |
<template>
<div class="parentBox">
<el-upload :accept="acceptAstrict" class="avatar-uploader" action="#" :http-request="uploadFiles" :show-file-list="false">
<div class="iconBox">
<i title="点击上传图片" v-if="!imgUrl" class="el-icon-plus avatar-uploader-icon"></i>
</div>
</el-upload>
<el-image v-if="imgUrl" :src="imgUrl" :preview-src-list="[imgUrl]"></el-image>
<div title="点击删除图片" v-if="imgUrl" class="gbtpBox" @click="imageRemove"><span>×</span></div>
</div>
</template>
<script>
import { uploadFiles } from '@api/zjmj/zdqyjg'//引入的接口文件
export default {
data() {
return {
acceptAstrict: '.jpg,.jpeg,.png,.JPG,.PNG', //文件上传限制
imgUrl: '' //图片地址
}
},
methods: {
//上传图片
uploadFiles(file) {
// 调用文件大小校验方法
if (this.beforeUpload(file.file)) {
this.formData = new FormData()
this.formData.append('file', file.file)
// 请求接口
uploadFiles(this.formData).then((res) => {
if (res.code == '10000') {
this.$message({
message: '上传成功',
type: 'success'
})
// 图片赋值
this.imgUrl = res.data.realPath
} else {
// 错误信息
this.$message({
message: res.msg,
type: 'error'
})
}
})
}
},
// 文件大小校验
beforeUpload(file) {
if (file.size > 10 * 1024 * 1024) {
this.$message('文件过大,请上传小于10MB的文件〜')
return false
}
return true
},
// 删除图片
imageRemove() {
this.imgUrl = ''
this.$message({
message: '删除图片成功',
type: 'success'
})
}
}
}
</script>
<style scoped>
.parentBox {
padding: 20px;
}
.iconBox i {
width: 100px;
height: 100px;
text-align: center;
line-height: 100px;
font-size: 20px;
color: #8c939d;
font-weight: bold;
border: 1px #8c939d dashed;
border-radius: 4px;
background: rgb(251, 253, 255);
}
.iconBox i:hover {
border: 1px rgb(64, 158, 255) dashed;
}
.el-image {
width: 100px;
height: 100px;
border-radius: 4px;
border: 1px solid rgb(192, 204, 218);
}
.gbtpBox {
position: relative;
}
.gbtpBox span {
position: absolute;
top: -110px;
left: 90px;
cursor: pointer;
font-size: 16px;
border-radius: 50%;
width: 16px;
height: 16px;
text-align: center;
line-height: 16px;
background: rgb(245, 108, 108);
color: #fff;
}
.gbtpBox span:hover {
background: rgb(247, 137, 137);
color: #fff;
}
::v-deep .avatar-uploader {
height: 0px;
}
</style>
上面我们实现的只能上传一张图片,那如果需求是可上传多张图片,就需要下面这种方式。
用到的属性
属性 | 描述 |
---|---|
multiple | 是否支持多选文件 |
on-exceed | 文件超出个数限制时的钩子 |
on-remove | 文件列表移除文件时的钩子 |
limit | 最大允许上传个数 |
before-upload | 上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传。 |
http-request | 覆盖默认的上传行为,可以自定义上传的实现 |
list-type | 文件列表的类型 |
on-preview | 点击文件列表中已上传的文件时的钩子 |
:class=“{hideShow: hideUpload}” | 当上传超过限制数量时,通过动态样式显隐上传图标 |
<template>
<div class="parentBox">
<el-upload :class="{hideShow: hideUpload}" :multiple="true" :on-exceed="onExceed" :on-remove="handleRemove" :limit="limit"
:before-upload="beforeUpload" action="" :http-request="uploadFiles" list-type="picture-card" :on-preview="handlePictureCardPreview">
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="imgUrl">
</el-dialog>
</div>
</template>
<script>
import { uploadFiles } from "@api/records";
export default {
data() {
return {
limit: 3, //最大上传数量
dialogVisible: false, //预览图片框
imgUrl: "", // 图片地址
fileList: [], //图片数组
};
},
// 上传超过限制后隐藏上传图标
computed: {
hideUpload() {
console.log(this.fileList.length);
console.log(this.limit);
return this.fileList.length >= this.limit;
},
},
methods: {
//上传图片方法
uploadFiles(file) {
let formData = new FormData();
formData.append("file", file.file);
// 请求接口
uploadFiles(formData).then((res) => {
if (res.code == "10000") {
this.fileList.push({
uid: file.file.uid,
url: res.data,
});
console.log(this.fileList);
this.$message({
message: res.msg,
type: "success",
});
} else {
// 错误信息
this.$message({
message: res.msg,
type: "error",
});
}
});
},
// 预览当前图片
handlePictureCardPreview(file) {
this.imgUrl = file.url;
this.dialogVisible = true;
},
// 删除当前图片
handleRemove(file, fileList) {
let index = this.fileList.findIndex((item) => {
return item.uid === file.uid;
});
this.fileList.splice(index, 1);
},
// 当前上传图片大小格式校验
beforeUpload(file) {
let fileArr = file.name.split(".");
let suffix = fileArr[fileArr.length - 1];
if (!/(jpg|jpeg|png|JPG|PNG|gif|GIF)/i.test(suffix)) {
this.$message("图片格式不正确");
return false;
}
if (file.size > 10 * 1024 * 1024) {
this.$message.warning("图片大小不能超过 10MB!");
return false;
}
return true;
},
// 文件上传超出个数
onExceed(files, fileList) {
this.$message(`最多上传 ${this.limit} 张图片`);
},
},
};
</script>
<style scoped>
::v-deep .el-upload--picture-card {
width: 100px;
height: 100px;
line-height: 109px;
}
::v-deep .el-upload-list--picture-card .el-upload-list__item {
width: 100px;
height: 100px;
}
/* 上传超过限制后隐藏上传图标 */
::v-deep .hideShow .el-upload--picture-card {
display: none;
}
</style>
这种情况多用于一个表单中有很多个上传的组件,在上传和删除都调用接口(以下案例上传成功后返回的信息就是删除所需要的参数),最后提交时就不用携带上传的数据了。
<template>
<div>
<el-upload :file-list="xszzp" :before-remove="setDataBeforeRemove" :multiple="true" :on-exceed="onExceed" :on-remove="xszzpRemove"
:limit="5" :before-upload="beforeUpload" action="#" :http-request="xszzpFiles" list-type="picture-card"
:on-preview="handlePictureCardPreview">
<i class="el-icon-plus">i>
el-upload>
div>
template>
<script>
import { uploads, deleteFiles } from "@/api/inspection/index";
export default {
data() {
return {
imgMap: new Map(),
xszzp: [], //存放图片的数组
};
},
mounted() {
// 模拟回显
this.xszzp = [
{
checklistId: 32,
url: "http://119.253.35.74:39000/defaults/20230320/4CD40BABF4B14231AF07E58DC78301C8.png",
id: 202,
moduleId: 54,
name: "20230320/4CD40BABF4B14231AF07E58DC78301C8.png",
realPath: "20230320/4CD40BABF4B14231AF07E58DC78301C8.png",
type: 1,
},
{
checklistId: 12,
url: "http://119.253.35.74:39000/defaults/20230320/2B1D3E48A01A4BD8B0FB97FE0047A01D.png",
id: 203,
moduleId: 43,
name: "20230320/2B1D3E48A01A4BD8B0FB97FE0047A01D.png",
realPath: "20230320/2B1D3E48A01A4BD8B0FB97FE0047A01D.png",
type: 1,
},
];
//接口回显
// taskCarView() {
// taskCarView().then((res) => {
// if (res.code == "10000") {
// this.ruleForm = res.data;
// // 行驶证回显
// if (res.data.xszImg) {
// res.data.xszImg.forEach((item) => {
// this.xszzp.push({
// checklistId: item.checklistId,
// url: item.enclosure,
// id: item.id,
// moduleId: item.moduleId,
// name: item.realPath,
// realPath: item.realPath,
// type: item.type,
// });
// });
// }
// }
// });
// },
},
methods: {
// 上传图片
xszzpFiles(file) {
// uid 是唯一的
let uid = file.file.uid;
let formData = new FormData();
formData.append("file", file.file);
uploads(formData).then((res) => {
if (res.code == "10000") {
this.imgMap.set(uid, res.data);
this.$message({
message: res.msg,
type: "success",
});
}
});
},
// 删除行驶证照片
xszzpRemove(file, flist) {
let uid = file.uid;
let targetImg = this.imgMap.get(uid);
// 删除所需的参数
let params = {
id: targetImg.id,
filePath: targetImg.realPath,
};
// 请求接口
deleteFiles(params).then((res) => {
if (res.code == "10000") {
this.$message({
message: res.msg,
type: "success",
});
}
});
},
//对于回显的数据删除之前,先获取图片数据存储到imgMap,用来给接口传id和url(公共)
setDataBeforeRemove(file, fileList) {
let uid = file.uid;
if (file.status == "success") {
//此状态为回显的数据
if (!this.imgMap.hasOwnProperty(uid)) {
this.imgMap.set(uid, file);
}
}
},
// 当前上传图片大小格式校验
beforeUpload(file) {
let fileArr = file.name.split(".");
let suffix = fileArr[fileArr.length - 1];
if (!/(jpg|jpeg|png|JPG|PNG|gif|GIF)/i.test(suffix)) {
this.$message("图片格式不正确");
return false;
}
if (file.size > 10 * 1024 * 1024) {
this.$message.warning("图片大小不能超过 10MB!");
return false;
}
return true;
},
// 预览图片
handlePictureCardPreview(file) {
this.imgDialog.dialogRow = file.url;
this.imgDialog.dialogLsattr = true;
},
// 文件上传超出个数
onExceed() {
this.$message(`最多上传 5 张图片`);
},
},
};
script>
⭐ element表格上传图片必看:如何避免全行上传?
⭐ 让图片上传变得更简单:vue和vant的完美融合
⭐ 小程序开发攻略:如何优雅地实现图片上传?