前言

功能说明

基于element-ui封装的uploadPic组件(vue2版本)

1.支持自定义图片和视频预览尺寸

2.弹框预览、可下载、删除。

3.可同时上传单个、多个,可混合上传图片或者视频。

实现

<template>
<div :style="{'--compWidth': width, '--compHeight': height}">
<el-upload :action="action" :file-list="fileList" :disabled="disabled" list-type="picture-card" :headers="headers" :limit="limit" :accept="accept" :class="(limit <= fileList.length) || uploading ? `hideUpload ${uploadCompSize}` : `${uploadCompSize}`" :on-error="handleError"
:before-upload="beforeUpload" :on-success="handleSuccess">
<i slot="default" class="el-icon-plus"></i>
<div slot="file" slot-scope="{ file }">
<img v-if="file.fileType == 'image'" class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
<video v-if="file.fileType == 'video'" controls="controls" :src="file.url" style="max-width:100%;max-height:100%"></video>
<span v-if="file.status === 'success'" class="el-upload-list__item-actions">
<span v-if="preview" class="el-upload-list__item-preview" @click="handleImgPreview(file)">
<i class="el-icon-zoom-in"></i>
</span>
<span v-if="download" class="el-upload-list__item-delete" @click="handleDownload(file)">
<i class="el-icon-download"></i>
</span>
<span v-if="deleted" class="el-upload-list__item-delete" @click="handleRemove(file)">
<i class="el-icon-delete"></i>
</span>
</span>
<span v-else :class="[uploading ? 'uploading' : '','el-upload-list__item-actions']">
<i class="el-icon-loading" /><i style="font-size: 14px">上传中</i>
</span>
</div>
<div slot="tip" v-if="tips" class="el-upload__tip">{{tips}}</div>

</el-upload>
<el-dialog :visible.sync="previewVisible" title="预览" width="fit-content" append-to-body>
<img v-if="previewImg.fileType == 'image'" :src="previewImg.url" style="height:60vh;margin: 0 auto;display: block;">
<video v-if="previewImg.fileType == 'video'" controls="controls" autoplay="autoplay" :src="previewImg.url" style="height:60vh;margin: 0 auto;display: block;"></video>
<div slot="footer">
<el-button @click="previewVisible=false">关闭</el-button>
</div>
</el-dialog>
</div>
</template>

<script>
import { getToken } from "@/util/auth";
export default {
name: 'UploadPic',
props: {
// 上传的地址
action: {
type: String,
default: '/api/blade-resource/oss/endpoint/put-file',
},
// 禁用
disabled: {
type: Boolean,
default: false
},
// 组件大小,也可以传compWidth、compHeight自定义
uploadCompSize: {
type: String,
default: 'small'
},
width: {
type: String,
default: '100px'
},
height: {
type: String,
default: '100px'
},
// 提示建议
tips: {
type: String,
default: ''
},
// v-model 双向绑定的value
value: {
type: [Array, String],
default: () => ([])
},
// 设置上传的请求头部
headers: {
type: Object,
default: () => {
return {
Authorization: "Basic c2FiZXI6c2FiZXJfc2VjcmV0",
"Blade-Auth": "Bearer " + getToken(),
}
},
},
// 上传文件大小限制, 默认5120 不限制,单位M
size: {
type: [Number, String],
default: 5120,
},
// 文件上传格式, 默认jpeg, png,jpg
accept: {
type: String,
default: 'image/jpeg,image/png,image/jpg,image/gif',
},
// 是否显示删除操作按钮
deleted: {
type: Boolean,
default: true,
},
// 是否显示预览操作按钮
preview: {
type: Boolean,
default: true,
},
// 是否显示下载操作按钮
download: {
type: Boolean,
default: false,
},
// 上传文件个数限制,默认1 不限制
limit: {
type: [Number, String],
default: 1,
},
},
data() {
return {
fileList: [], // 默认文件列表
hideUpload: false, // 超出限制隐藏上传按钮
uploading: false, // 是否上传中,上传时隐藏上传按钮
previewImg: {url: ''}, // 预览图片地址
previewVisible: false, // 是否显示预览
}
},
watch: {
value: {
handler(newVal) {
if (newVal && newVal.length) {
if (Array.isArray(newVal)) {
this.fileList = newVal.filter(Boolean).map((url) => {
let res = this.handleCheckFileType(url)
return { url,fileType: res}
});
} else {
this.fileList = Array.from([newVal]).filter(Boolean).map((url) => {
let res = this.handleCheckFileType(url)
return { url,fileType: res }
})
}
}
},
immediate: true,
deep: true
}
},
mounted() {
},
methods: {
// 上传前文件大小判断
beforeUpload(file) {
const { size,accept } = this;
const type = file.type;
if (accept && accept.indexOf(type) === -1) {
this.$message.error(`上传文件失败,文件只支持${accept}类型!`)
return false
}
const overSize = size > 0 && file.size < 1024 * 1024 * size
if (!overSize) this.$message.error(`上传文件大小不能超过 ${size}MB!`)
this.uploading = overSize // 是否上传中
return overSize
},
// 上传出错返回
handleError(event, file, fileList) {
this.$message.error('上传失败!')
this.handleChange()
},
handleSuccess(res, file, list) {
this.fileList.push({ url: res.data.link })
this.handleChange()
},
// 删除图片
handleRemove(file) {
const { fileList } = this
this.fileList = fileList.filter((item) => item.uid !== file.uid)
this.handleChange();
},
handleCheckFileType(file) {
const index = file.lastIndexOf('.');
const fileType = file.substr(index + 1)
let type = '';
if (['mp4','flv','avi','mov','wmv','mpg'].includes(fileType)) {
type = 'video'
} else {
type = 'image'
}
return type
},
// 图片预览
handleImgPreview(file) {
this.previewImg = file
this.$nextTick(() => {
this.previewVisible = true
})
},
handleChange() {
const { limit, fileList } = this
if (limit > 0 && fileList.length >= limit) {
this.hideUpload = true
} else { this.hideUpload = false }
this.uploading = false
let fileArr = []
if (limit === 1 && fileList.length) {
fileArr = fileList[0].url || '';
} else if (!fileList.length) {
// 解决不必填情况下 默认抛出空字符串
fileArr = '';
} else {
fileList.forEach((item) => fileArr.push(item.url))
}
this.$emit('input', fileArr)
},
handleDownload(file) {
const a = document.createElement('a')
a.href = file.url
a.click()
},
},
}
</script>

<style lang="scss">
:root {
--compWidth: 100px;
--compHeight: 100px;
}
.hideUpload .el-upload--picture-card {
display: none;
}
.el-upload--picture-card {
width: 100px;
height: 100px;
line-height: 100px;
}
.mini .el-upload-list--picture-card .el-upload-list__item,
.mini .el-upload--picture-card {
width: 70px;
height: 70px;
line-height: 70px;
}
.small .el-upload-list--picture-card .el-upload-list__item,
.small .el-upload--picture-card {
width: var(--compWidth);
height: var(--compHeight);
line-height: var(--compHeight);
}
.large .el-upload-list--picture-card .el-upload-list__item,
.large .el-upload--picture-card {
width: 150px;
height: 150px;
line-height: 150px;
}
.el-upload-list--picture-card .uploading.el-upload-list__item-actions {
opacity: 1;
}
.el-upload-list--picture-card .el-upload-list__item {
width: 100px;
height: 100px;
}
.el-upload__tip {
line-height: 20px;
font-size: 12px;
color: #999999;
}
/*添加、删除文件时去掉动画过渡*/
.el-upload-list__item {
transition: none !important;
}
</style>