使用方式
<upload-img :maxLength="6"
limit-type=".png,.jpg,.jpeg"
:filesList="checkFileList"
@addFileList="checkFileUpdate" @deleteFileList="checkFileDelete"></upload-img>
可选属性
属性名称 | 属性说明 |
---|---|
show-loading | 是否展示上传时的loading |
max-length | 可上传的最大文件数量 |
files-list | 回显的图片集合 |
type | 上传按钮样式类型 0:图片 1:按钮 |
disabled | 是否禁用上传 |
can-delete | 是否允许删除文件 |
folder | 文件在服务器上的文件夹,如minio中基础文件夹的下一级文件夹 |
max-size | 允许上传的最大文件大小,单位M |
limit-type | 所允许上传的文件类型,比如设置limit-type = '.png,.jpg,.jpeg’则限值上传图片类型,为空时允许上传所有类型文件 |
回调事件
事件名称 | 事件说明 |
---|---|
deleteFileList | 删除文件时触发,将删除文件后获取到的文件信息返回 |
addFileList | 新增文件时触发,将上传文件后获取到的文件信息返回 |
组件代码
<template>
<div class="imgList">
<div>
<div
class="img"
v-show="item.url"
v-for="(item, index) in upFileList"
:key="index"
draggable="true"
@dragstart="dragstartEventImg($event, index)"
@dragenter="dragenterEventImg($event, index)"
@dragend="dragendEventImg($event, index)"
@dragover="dragoverEventImg">
<el-tooltip class="item" effect="dark" :content="item.name" placement="top-start">
<img v-if="['png', 'jpg', 'jpeg'].find(function(ii,index,arr){return ii === getFileType(item.url)})"
:src="fileOnlineShow + item.url" alt="" @click="previewFile(fileOnlineShow + item.url)"/>
<svg-icon
v-else-if="['doc', 'docx', 'xls', 'xlsx', 'pdf'].find(function(ii,index,arr){return ii === getFileType(item.url)})"
:icon-class="getFileType(item.url)"></svg-icon>
<svg-icon v-else icon-class="other"></svg-icon>
</el-tooltip>
<i
v-if="canDelete"
class="el-icon-error"
@click="deleteFile(item)"
></i>
</div>
</div>
<div
class="uploadFile"
:class="{ disabledStyle: disabled }"
v-show="maxLength > filesList.length"
>
<el-upload
:disabled="disabled"
:multiple="true"
name="file"
ref="imageUpload"
:headers="headers"
:before-upload="beforeUploadFile"
:data="{ folder: folder }"
:show-file-list="false"
:action="fileUploadApi"
:on-success="uploadFile"
:limit="maxLength"
:file-list="filesList"
:on-progress="progress"
:on-exceed="onExceed"
:on-error="onError"
:accept="limitType"
lazy
>
<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>
</template>
<script>
import store from "@/store";
import {mapGetters} from "vuex";
import Base64 from "@/utils/base64";
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,
},
// 基础子文件夹
folder: {
type: String,
default: 'imsp'
},
// 最大允许上传的文件大小,默认单位M
maxSize: {
type: Number,
default: 100
},
// 限制的文件类型
limitType: {
type: String,
default: ''
}
},
data() {
return {
headers: {
'Authorization': 'Bearer ' + store.getters.access_token
},
upFileList: [],
percentage: 0,
fileName: '',
status: null,
progressShow: false,
showBigImg: '',
dialogVisible: false,
tempArr: [],
startImgIndex: '', //拖动前图片index
endImgIndex: '', // 结束拖动的index
cancelUpload: false,
}
},
computed: {
// fileOnlineShow是根据文件路径获取文件流的后端controller接口地址,如果是直接用nginx代理,则为nginx配置的路径
// fileUploadApi是上传文件的接口地址
...mapGetters(['fileUploadApi', 'fileOnlineShow'])
},
components: {},
mounted() {
this.upFileList = this.filesList
},
watch: {
filesList(val) {
this.upFileList = val
},
},
methods: {
// 拖动开始
dragstartEventImg($event, index) {
this.startImgIndex = index
},
// 拖动时
dragenterEventImg($event, index) {
this.endImgIndex = index
},
// 拖动结束
dragendEventImg($event, index) {
const currRow = this.upFileList.splice(this.startImgIndex, 1)[0]
this.upFileList.splice(this.endImgIndex, 0, currRow)
// this.$emit('getImgList', this.upFileList)
},
// 放置
dragoverEventImg(e) {
e.preventDefault()
},
// 预览文件
previewFile(file) {
window.open("https://preview.allbs.cn/onlinePreview?url=" + encodeURIComponent(new Base64().encode(location.origin + file)));
},
format(percentage) {
return percentage === 100 ? '99%' : `${percentage}%` //防止到100时后端处理要时间,会卡在100一小段时间,优化体验
},
// 超出限制
onExceed() {
this.$message.error('选择的文件超出个数限制')
},
// 删除图片
deleteFile(item) {
this.upFileList.splice(this.upFileList.findIndex(item => item.fileId === item.fileId), 1)
console.log("删除文件" + item.fileId);
this.$emit('deleteFileList', item.fileId)
},
// 上传时的钩子
progress(event, file, fileList) {
this.progressShow = true
this.percentage = Math.ceil(event.percent)
if (this.cancelUpload) {
this.$refs.imageUpload.abort()
this.$message.error('文件已取消上传')
this.upFileList = this.upFileList.filter((item) => {
return item.url
})
this.progressShow = false
}
},
// 上传失败
onError(err, file, fileList) {
this.$message.error('文件上传失败')
this.progressShow = false
this.status = null
this.percentage = 0
this.fileName = ''
},
// 文件上传前
beforeUploadFile(file) {
this.cancelUpload = false
if (file.size / 1024 / 1024 >= this.maxSize) {
this.$message.error('只能上传小于' + this.maxSize + 'M的图片!')
return false
}
},
// 文件上传成功
uploadFile(response, file, fileList) {
if (response.code === 200) {
this.upFileList.push(response.data)
this.$emit('addFileList', response.data.fileId)
this.$message.success('文件上传成功')
} else {
this.$message.error('文件上传失败')
}
// 进度条消失
this.progressShow = false
this.status = null
this.percentage = 0
this.fileName = ''
},
getFileType(url) {
return url.substring(url.lastIndexOf(".") + 1, url.length);
},
},
}
</script>
<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;
&::before {
cursor: pointer;
}
}
}
}
}
.normal {
&:hover {
color: #5d8eff !important;
background-color: #fff !important;
border-color: #5d8eff !important;
}
&::before {
content: '';
cursor: pointer;
background-image: url('/assets/images/upload.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;
}
/deep/ .svg-icon {
width: 64px;
height: 64px;
cursor: pointer;
}
</style>
涉及到的svg图片
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 allbs!
评论