在我们日常的开发工作中时长会用到upload上传图片的时候,这里在components中封装了一个上传图片的组件,每次需要用到时候直接引用就可以了,就不用每次写upload了。
注明:此次封装适用于form表单中仅支持上传一个文件的时候使用!
第一步:创建pic-upload文件
pic-upload 为封装的upload组件:
第二步:在pic-upload中写入上传的模板
这里的readonly是用来控制当前是否为图片详情的情况
uploadUrl 代表要上传图片时自己公司的上传图片对应的api接口,具体根据自己项目的实际情况去拼接,我这个项目是这样拼接的,应该看着很醒目吧,
this.uploadUrl = `http://127.0.0.1:3000/oss/file/upload?access_token=${Cookies.get('access_token')}`
show-file-list 代表是否显示已上传文件列表(默认为true)
on-success 代表文件上传成功时的钩子,对应methods中的handleAvatarSuccess方法
如下:
handleAvatarSuccess(res) { //res为调用api接口成功后返回的参数数据
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.$emit('input', res.data.url) //这里直接给父组件中的v-model绑定成功的url。
}
before-upload 代表上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传。(我们可以在这里做一些格式或者大小的校验)
如下:
beforeAvatarUpload(file) { //file为默认参数,若返回 false 或者返回 Promise 且被 reject,则停止上传。
const isJPG = this.fileFormat.some(item => 'image/' + item === file.type)
const isLt2M = file.size / 1024 / 1024 < this.sizeLimit
if (!isJPG) {
this.$message.error(`上传图片只能是 ${this.fileFormat.toString()} 格式!`)
}
if (!isLt2M) {
this.$message.error(`上传图片大小不能超过 ${this.sizeLimit}MB!`)
}
return isJPG && isLt2M
},
其实element-ui中还有很多一些事件钩子函数用法,我这里只用到了这些,可以根据实际情况去调整,详情可以去element-ui官网查看。
如下就是html模快的代码:
<template>
<div class="load-wrap" :class="readonly ? 'readonly' : ''">
<el-upload
:action="uploadUrl"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<div v-if="value" class="pic-wrap">
<el-image :src="value" :preview-src-list="previewList" />
<div class="pic-mask">
<span>图片已上传</span>
<span>点击重新上传</span>
</div>
</div>
<i v-else class="el-icon-plus uploader-icon" />
</el-upload>
<div class="title">{
{ title }}</div>
</div>
</template>
第三步:js部分
首先是引入了cookes,因为我的token是存储在cookes中的。
如下:
import Cookies from 'js-cookie'
然后通过props接收父组件传输过来的参数值,通过响应的方法去操作某些数据的变化。
话不多说,直接上代码吧:
props: {
title: { //title名称
type: String,
default: ''
},
value: { //v-model绑定数据
type: String,
default: ''
},
fileFormat: { //图片验证格式
type: Array,
default: () => ['image/jpeg', 'image/jpg']
},
sizeLimit: { //图片验证大小
type: Number,
default: 3
},
readonly: { // 是否为预览模式
type: Boolean,
default: false
},
pic: { //上传多图片时路径
type: Array,
default: () => []
}
}
第四步:样式部分
样式做了简单的修整,可以根据自己的需求自行更改,这里可以仅做参考。
pic-upload所有代码:
<template>
<div class="load-wrap" :class="readonly ? 'readonly' : ''">
<el-upload
:action="uploadUrl"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<div v-if="value" class="pic-wrap">
<el-image :src="value" :preview-src-list="previewList" />
<div class="pic-mask">
<span>图片已上传</span>
<span>点击重新上传</span>
</div>
</div>
<i v-else class="el-icon-plus uploader-icon" />
</el-upload>
<div class="title">{
{ title }}</div>
</div>
</template>
<script>
import Cookies from 'js-cookie'
export default {
props: {
title: {
type: String,
default: ''
},
value: {
type: String,
default: ''
},
fileFormat: {
type: Array,
default: () => ['jpeg', 'jpg']
},
sizeLimit: {
type: Number,
default: 3
},
readonly: {
type: Boolean,
default: false
},
pic: {
type: Array,
default: () => []
}
},
data() {
return {
uploadUrl: '',
previewList: []
}
},
watch: {
value(val) {
if (val && this.readonly) {
this.clickImg()
} else {
this.previewList = []
}
}
},
mounted() {
this.uploadUrl = `${
window.SITE_CONFIG['apiURL']
}/oss/file/upload?access_token=${Cookies.get('access_token')}`
},
methods: {
clickImg() {
this.previewList = []
this.pic.forEach((item) => {
if (item.picUrl) {
this.previewList.push(item.picUrl)
}
})
},
beforeAvatarUpload(file) {
const isJPG = this.fileFormat.some(item => 'image/' + item === file.type)
const isLt2M = file.size / 1024 / 1024 < this.sizeLimit
if (!isJPG) {
this.$message.error(`上传图片只能是 ${this.fileFormat.toString()} 格式!`)
}
if (!isLt2M) {
this.$message.error(`上传图片大小不能超过 ${this.sizeLimit}MB!`)
}
return isJPG && isLt2M
},
handleAvatarSuccess(res) {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.$emit('input', res.data.url)
}
}
}
</script>
<style lang="scss" scoped>
.load-wrap {
display: flex;
flex-direction: column;
align-items: center;
width: 180px;
.title {
color: #999;
font-size: 12px;
line-height: 1;
}
}
:deep(.el-upload) {
border: 1px dashed #d9d9d9;
border-radius: 6px;
//cursor: pointer;
position: relative;
overflow: hidden;
&:hover {
border-color: #409eff;
color: #fff;
}
}
.uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.pic-wrap {
width: 178px;
height: 178px;
position: relative;
.el-image {
width: 100%;
height: 100%;
object-fit: contain;
}
&:hover .pic-mask {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.pic-mask {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.6);
}
}
.load-wrap.readonly .pic-wrap:hover .pic-mask {
display: none;
}
</style>
第五步:在父组件中使用:
先引入组件进来
import PicUpload from '@/components/pic-upload'
在components中定义
components: { PicUpload },
在页面中使用
<pic-upload
v-model="idCardPortrait"
title="身份证人像页"
:file-format="FormatList"
:size-limit="3"
:pic="dataForm.bizEscortPics"
:readonly="detail"
/>
父组件中所有代码:
<template>
<el-dialog
:visible.sync="visible"
title="新增"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<el-form
ref="dataForm"
v-loading="loadingData"
:model="dataForm"
:rules="dataRule"
label-width="180px"
>
<el-form-item prop="idCardPic" label="押运员身份证">
<pic-upload
v-model="idCardPortrait"
title="身份证人像页"
:file-format="FormatList"
:size-limit="3"
:pic="dataForm.bizEscortPics"
:readonly="detail"
/>
<pic-upload
v-model="idCardPortrait"
title="身份证国徽页"
:file-format="FormatList"
:size-limit="3"
:pic="dataForm.bizEscortPics"
:readonly="detail"
/>
</el-form-item>
<el-form-item prop="idCardPic" label="从业资格证">
<pic-upload
v-model="certificate"
title="从业资格证"
:pic="dataForm.bizEscortPics"
:readonly="detail"
/>
</el-form-item>
</el-form>
</el-dialog>
</template>
<script>
import PicUpload from './pic-upload'
export default {
components: { PicUpload },
data() {
return {
visible: false,
FormatList: ['jpg', 'png', 'jpeg'],
dataForm: {
bizEscortPics: [
{ picType: 1, picUrl: '' }, // 身份证人像
{ picType: 2, picUrl: '' }, // 身份证国徽
{ picType: 5, picUrl: '' } // 从业资格证
]
}
}
}
</script>