自己封装el-upload组件,可直接使用,持续更新完善中
子组件:
<div class="imgList">
<div v-if="showImages">
<div
class="img"
v-show="item.url"
v-for="(item, index) in filesList"
:key="index"
draggable="true"
@dragstart="dragstartEventImg($event, index)" // 用于拖拽时的方法,用于调换图片位置
@dragenter="dragenterEventImg($event, index)" // 用于拖拽时的方法,用于调换图片位置
@dragend="dragendEventImg($event, index)" // 用于拖拽时的方法,用于调换图片位置
@dragover="dragoverEventImg" // 用于拖拽时的方法,用于调换图片位置
>
<img :src="item.url" alt="" @click="lookBigImg(item.url)" /> //点击看大图
<i
v-if="canDelete"
class="el-icon-error"
@click="deleteImg(item.url)"
></i>
</div>
</div>
<div
class="uploadImg"
:class="{ disabledStyle: disabled }"
v-show="maxLength > filesList.length"
>
<el-upload
:disabled="disabled" // 是否禁止上传
:multiple="true" // 是否可上传多张
name="files"
ref="imageUpload"
:headers="headers" // 放请求头
:before-upload="beforeUploadImg" // 图片上传前
:data="{ fileType: 1 }" // 额外参数:上传类型
:show-file-list="false" // 是否显示已上传文件列表,默认样式如下图,选择false为自定义已上传文件列表
:action="uploadUrl" // 上传接口
:on-success="uploadImg" // 图片上传成功的回调
:limit="maxLength" // 最多上传多少张
:file-list="filesList" // 已上传图片的列表,不设置的话limit检测不了,会导致删除图片后上传按钮无法点击
:on-progress="progress" // 上传时的钩子,可检测上传到百分之多少
:on-exceed="onExceed" // 选择的文件超出限制就触发
:on-error="onError" // 上传失败触发
>
<div :disabled="disabled" class="uploadBtn" v-if="type === 0">
<i class="el-icon-plus"></i>
</div>
<el-button
:disabled="disabled"
size="small"
class="normal"
v-else-if="type === 1"
>上传文件</el-button
>
</el-upload>
</div>
<div class="uploading" v-if="showLoading" v-show="progressShow">
<div class="left">
<i class="el-icon-paperclip"></i>
</div>
<div class="right">
<div class="right-top">
<span>{{ fileName }}</span>
<i class="el-icon-close" @click="cancelUpload = true"></i>
</div>
<div class="right-bottom">
<el-progress
:percentage="percentage"
:format="format"
:stroke-width="2"
:status="status"
></el-progress>
</div>
</div>
</div>
</div>
下面贴上js代码
export default {
props: {
//是否展示上传时的loading
showLoading: {
type: Boolean,
default: true,
},
maxLength: {
// 可上传的最大数量
type: Number,
default: 1,
},
// 图片集合
filesList: {
type: Array,
default: () => [],
},
// 上传按钮样式类型
type: {
type: Number,
default: 0,
},
// 是否禁用
disabled: {
type: Boolean,
default: false,
},
// 是否可删除图片
canDelete: {
type: Boolean,
default: true,
},
// 是否展示图片
showImages: {
type: Boolean,
default: true,
},
},
data() {
return {
uploadUrl: `${baseUrl}/common/uploadFile`, //上传的接口
headers: { Authorization: localStorage.getItem('token') },
upImgList: [],
percentage: 0,
fileName: '',
status: null,
progressShow: false,
showBigImg: '',
dialogVisible: false,
tempArr: [],
startImgIndex: '', //拖动前图片index
endImgIndex: '', // 结束拖动的index
cancelUpload: false,
}
},
mounted() {
this.upImgList = this.filesList
},
watch: {
filesList(val) {
this.upImgList = val
},
},
methods: {
// 拖动开始
dragstartEventImg($event, index) {
this.startImgIndex = index
},
// 拖动时
dragenterEventImg($event, index) {
this.endImgIndex = index
},
// 拖动结束
dragendEventImg($event, index) {
const currRow = this.upImgList.splice(this.startImgIndex, 1)[0]
this.upImgList.splice(this.endImgIndex, 0, currRow)
this.$emit('getImgList', this.upImgList)
},
// 放置
dragoverEventImg(e) {
e.preventDefault()
},
// 查看大图
lookBigImg(url) {
this.showBigImg = url
this.dialogVisible = true
},
format(percentage) {
return percentage === 100 ? '99%' : `${percentage}%` //防止到100时后端处理要时间,会卡在100一小段时间,优化体验
},
// 超出限制
onExceed() {
this.$message.error('选择的文件超出个数限制')
},
// 删除图片
deleteImg(item) {
for (let i = 0; i < this.upImgList.length; i++) {
if (this.upImgList[i].url === item) {
this.upImgList.splice(i, 1) // 将使后面的元素依次前移,数组长度减1
i-- // 如果不减,将漏掉一个元素
}
}
this.$emit('getImgList', this.upImgList)
},
// 上传时的钩子
progress(event, file, fileList) {
this.progressShow = true
this.percentage = Math.ceil(event.percent)
if (this.cancelUpload) {
this.$refs.imageUpload.abort()
this.$message.error('文件已取消上传')
this.upImgList = this.upImgList.filter((item) => {
return item.url
})
this.$emit('getImgList', this.upImgList)
this.progressShow = false
}
},
// 上传失败
onError(err, file, fileList) {
this.upImgList.forEach((element, index) => {
if (element.uid === file.uid) {
this.upImgList.splice(index, 1) // 上传失败删除该记录
this.$message.error('文件上传失败')
this.$emit('getImgList', this.upImgList)
this.progressShow = false
this.status = null
this.percentage = 0
this.fileName = ''
}
})
},
//图片上传前
beforeUploadImg(file) {
this.cancelUpload = false
let allowType = ['image/png', 'image/jpeg']
if (allowType.indexOf(file.type) === -1) {
this.$message.error('上传图片只能是 JPG、PNG 格式!')
return false
}
if (file.size / 1024 / 1024 >= 3) {
this.$message.error('只能上传小于3M的图片!')
return false
}
this.fileName = file.name
this.objAddItem(this.upImgList, file)
},
// 图片上传成功
uploadImg(response, file, fileList) {
let num = 0
this.upImgList.forEach((item, index) => {
if (item.uid === file.uid) {
let ele = {
uid: item.uid,
url: response.data.fileUrl,
}
this.$set(this.upImgList, index, ele)
}
if (item.url === '') {
num++
}
})
this.$emit('getImgList', this.upImgList)
if (num === 1) {
this.progressShow = false //进度条消失
this.status = null
this.percentage = 0
this.fileName = ''
}
},
objAddItem(tempArr, file) {
const tempObj = {
uid: file.uid, // uid用于辨别文件
url: '',
}
tempArr.push(tempObj)
},
},
}
样式部分
<style lang="scss" scoped>
.imgList {
display: flex;
flex-wrap: wrap;
div {
.img {
position: relative;
img {
cursor: pointer;
width: 64px;
height: 64px;
display: inline-block;
}
width: 64px;
height: 64px;
display: inline-block;
margin-right: 8px;
.el-icon-error {
font-size: 16px;
position: absolute;
right: -8px;
top: -8px;
color: red;
}
}
}
}
.normal {
&:hover {
color: #5d8eff !important ;
background-color: #fff !important ;
border-color: #5d8eff !important ;
}
&::before {
content: '';
background-image: url('@/assets/images/upload2.png');
background-size: 14px 14px;
display: inline-block;
width: 14px;
height: 14px;
transform: translateY(2px);
margin-right: 6px;
}
}
.uploadBtn {
width: 64px;
height: 64px;
background: #f7f8fa;
border: 1px solid #ebebe8;
position: relative;
i {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #bebec5;
font-size: 24px;
}
}
.uploading {
display: flex;
width: 162px;
margin-left: 8px;
margin-top: 28px;
.left {
margin-right: 8px;
i {
display: inline-block;
width: 14px;
height: 14px;
color: #000;
}
}
.right {
width: 140px;
.right-top {
display: flex;
justify-content: space-between;
span {
height: 22px;
font-size: 14px;
font-weight: 400;
color: rgba(0, 0, 0, 0.45);
line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 130px;
}
}
}
.el-icon-close {
line-height: 22px;
}
}
.disabledStyle {
cursor: not-allowed;
}
</style>
父组件使用:
<uploadImg
:maxLength="6"
:filesList="filesList"
@getImgList="getImgList" // 数据更新时触发
/>
其他功能可根据子组件的props来设置