效果图
组件代码 自行参考
<template>
<div class="img-upload" :class="sizeClass" style="margin-bottom: 10px" :style="'height:'+size+'px;width:'+size+'px'">
<a-upload
:action="uploadAction"
list-type="picture-card"
:file-list="fileList"
:beforeUpload="beforeUpload"
v-bind="$attrs"
:disabled="disabled"
:remove="removeFile"
:accept="acceptType"
:headers="{workNo: userInfo.workNo, 'X-Access-Token': token}"
>
<div v-if="fileList.length < limit">
<a-icon type="plus" />
<div class="ant-upload-text">
{{ placeholder }}
</div>
<div style="margin-top:8px;color:rgba(0, 0, 0, 0.4)">
仅支持 PDF、JPG 和 PNG 格式。最大文件尺寸 10 MB
</div>
<div style="margin-top:2px;color:rgba(0, 0, 0, 0.4)">
(图片比例670*320)
</div>
</div>
</a-upload>
<a-modal :visible="previewVisible" title="预览" :footer="null" @cancel="handleCancel">
<img v-if="showImagePreview" alt="图片" style="width: 100%" :src="previewImage" />
<video v-else-if="showVideoPreview&&previewVisible" autoplay style="width: 100%" :src="previewImage"></video>
</a-modal>
</div>
</template>
<script>
import { USER_INFO, ACCESS_TOKEN } from "@/store/mutation-types"
import Vue from 'vue'
function getBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}
export default {
name: "ImgUpload",
props: {
uri: {
type: String,
default: 'mm/mmWechatWelcomeMsg/upload'
},
value: {
type: Array,
default: () => ([])
},
limit: {
type: Number,
default: Infinity
},
disabled: {
type: Boolean,
default: false
},
fileType: {
type: String,
default: 'image'
},
size: {
type: Number,
default: 100
},
placeholder: {
type: String,
default: '点击上传'
}
},
data () {
return {
previewVisible: false,
previewImage: '',
fileList: this.value||[],
userInfo: Vue.ls.get(USER_INFO),
token: Vue.ls.get(ACCESS_TOKEN)
}
},
watch: {
value (val) {
this.fileList = val||[]
}
},
computed: {
showImagePreview () {
return ['image', '.jpg', '.png', '.jpeg', '.gif'].some(item => this.fileType.includes(item))
},
showVideoPreview () {
return ['.mp3', '.mp4', '.acc', 'audio', 'video'].some(item => this.fileType.includes(item))
},
uploadAction () {
return `${window._CONFIG['domianURL']}/${this.uri}`;
},
sizeClass () {
return 'img-size-'+this.size
},
acceptType () {
if (this.fileType == 'image') {
return 'image/*'
} else if (this.fileType == 'video') {
return 'video/*'
} else if (this.fileType == 'audio') {
return 'audio/*'
}
return this.fileType
}
},
methods: {
beforeUpload(file) {
return new Promise((resolve, reject) => {
let isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'|| file.type === 'image/jpg';
if (!isJpgOrPng) {
this.$message.error('格式错误,只能上传jpg、jpeg、png');
return reject(false);
}
let w = 0,h = 0;
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload=()=>{
const image = new Image();
image.src = reader.result;
image.onload=()=>{
w = image.width;
h = image.height;
const ratio = 670/320
if(w/h == ratio){ // 图片比例为670*320横纵比一致
return resolve(true);
}else{
this.$message.error('图片尺寸错误,只能上传670x320横纵比一致的图片');
return reject(false);
}
}
}
let isLt1M = file.size / 10240 / 10240 <= 1;
if (!isLt1M) {
this.$message.error('图片大小超过10MB!');
return reject(false);
}
return isJpgOrPng && isLt1M;
})
},
removeFile (file) {
this.$emit('delete', file)
if (this.limit == 1) {
this.$emit('change', [])
}
return true
},
handleCancel() {
this.previewVisible = false;
},
async handlePreview(file) {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj);
}
this.previewImage = file.url || file.preview;
this.previewVisible = true;
},
handleChange({ file,fileList }) {
this.fileList = fileList
if (file.status === 'done') {
for (let i = this.fileList.length-1;i>=0;--i) {
const tempFile = this.fileList[i]
if (tempFile.response && tempFile.response.success) {
this.$set(this.fileList, i, {
uid: tempFile.response.result.id,
name: tempFile.response.result.fileName,
url: tempFile.response.result.url,
status: 'done'
})
} else if (!tempFile.url){
this.$message.error('上传失败,请重试!')
this.fileList.splice(i,1)
}
}
this.$emit('change', this.fileList)
} else if (file.status === 'error') {
this.$message.error('上传失败,请重试!')
this.fileList = this.fileList.filter(item => item.status !== 'error')
}
this.$emit('input', this.fileList)
},
}
}
</script>
<style scoped lang="less">
.img-upload {
&.img-size-100 {
/deep/.ant-upload-list-picture-card-container {
width: 425px;
height: 152px;
}
/deep/.ant-upload.ant-upload-select-picture-card {
width: 425px;
height: 152px;
}
/deep/.ant-upload-list-picture-card .ant-upload-list-item {
width: 425px;
height: 152px;
}
.ant-upload-select-picture-card .ant-upload-text {
color: #666;
display: block;
}
}
&.img-size-50 {
/deep/.ant-upload-list-picture-card-container {
width: 50px;
height: 50px;
}
/deep/.ant-upload.ant-upload-select-picture-card {
width: 50px;
height: 50px;
}
/deep/.ant-upload-list-picture-card .ant-upload-list-item {
width: 50px;
height: 50px;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
display: none;
}
}
}
/deep/.ant-upload-list-picture .ant-upload-list-item,
/deep/.ant-upload-list-picture-card .ant-upload-list-item{
padding: 0;
}
.ant-upload-select-picture-card i {
font-size: 32px;
color: #999;
}
</style>