目录
- ElementUI的el-upload组件二次封装问题
- 组件
- 使用
- el-upload组件封装后更好用了
- 组件截图
- 组件代码部分
ElementUI的el-upload组件二次封装问题
开发工作中我们都会遇到图片上传的问题,虽说ElementUI已有提供图片上传的组件,但我们用到图片上传的地方肯定不止一处的,并且框架自带的组件并不能完全满足我们的需求,为此我对原有组件做了二次封装,做到一次封装,到处使用!
直接上代码:
组件
**uploadImg.vue** | |
<template> | |
<div> | |
<el-upload :disabled="idCardIsUpload" class="avatar-uploader" action="" list-type="picture" :show-file-list="false" :http-request="diyRequest"> | |
<el-image v-if="idCardImgUrl" :src="idCardImgUrl" name="idCardImgUrl" class="avatar" @error="imgLoadError"></el-image> | |
<el-progress style="margin: 5px;" :width='70' v-else-if="idCardIsUpload" type="circle" :percentage="idCardUploadPercentage"></el-progress> | |
<div v-else class="div-plus"> | |
<i class="el-icon-plus avatar-uploader-icon"></i> | |
</div> | |
</el-upload> | |
</div> | |
</template> | |
<script> | |
export default { | |
data() { | |
return { | |
idCardImgUrl: '', | |
idCardIsUpload: false, | |
idCardUploadPercentage: 0, | |
errorImgUrls: [], | |
} | |
}, | |
props: { | |
/*可以在使用组件的时候传入一个支持上传的图片格式的数组进来,不传默认default数组*/ | |
supportType: {//支持上传文件的格式 | |
default: () => ['image/jpeg', 'image/jpg', 'image/png'], | |
type: Array | |
} | |
}, | |
methods: { | |
/*父组件执行的方法*/ | |
setEditImg(path) { | |
this.idCardImgUrl = path ? path : '' | |
}, | |
/*自定义上传的方法*/ | |
diyRequest(param) { | |
/*对上传图片的大小和格式校验*/ | |
const isLt10M = param.file.size / 1024 / 1024 < 4 | |
if (this.supportType.indexOf(param.file.type) == -1) { | |
let supportType = this.supportType | |
let msg = '' | |
supportType.map(res => { | |
msg += res.substring(6) + '/' | |
}) | |
let newMsg = msg.slice(0, (msg.length) - 1) | |
this.$Message('error', `请上传正确的图片格式!支持的格式有:` + newMsg) | |
return | |
} | |
if (!isLt10M) { | |
this.$Message('error', '上传图片大小不能超过4MB哦!') | |
return | |
} | |
const fileObj = param.file | |
const form = new FormData() | |
form.append('file', fileObj) | |
let callback = (progress) => { | |
this.idCardIsUpload = true | |
this.idCardUploadPercentage = progress | |
} | |
/*走后台接口,这里自行换成自己的api*/ | |
this.$api.addUploadImg(form, callback).then(res => { | |
this.idCardIsUpload = false | |
this.idCardUploadPercentage = 0 | |
if (res.code == 200) { | |
this.idCardImgUrl = res.data.basePath + res.data.url | |
/*成功之后将图片路径暴露给父组件去显示图片*/ | |
this.$emit('setCardPic', res.data.url) | |
} else { | |
this.$Message('error', res.message) | |
} | |
}) | |
}, | |
/*当图片显示失败的时候,我会重复10次赋值图片,成功显示就退出,还是失败就会显示失败*/ | |
imgLoadError(error) { | |
let isExist = false | |
const src = error.path[0].src.split('?')[0] | |
if (this.errorImgUrls.length == 0) { | |
this.errorImgUrls.push({ 'src': src, 'number': 1 }) | |
} | |
for (let i = 0; i < this.errorImgUrls.length; i++) { | |
if (src === this.errorImgUrls[i].src) { | |
isExist = true | |
while (this.errorImgUrls[i].number < 10) { | |
console.log('我在重复赋值...') | |
this.errorImgUrls[i].number++ | |
const timestamp1 = Date.parse(new Date()) | |
this[error.path[0].name] = src + '?t=' + timestamp1 | |
} | |
} | |
} | |
if (!isExist) {//首次上传(不在错误数组图片中,需要执行循环三次赋值) | |
this.errorImgUrls.push({ 'src': src, 'number': 1 }) | |
this.imgLoadError(error) | |
} | |
}, | |
} | |
} | |
</script> | |
<style lang="scss" scoped> | |
.div-plus { | |
width: 174px; | |
height: 174px; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
} | |
</style> | |
<style lang="scss"> | |
.avatar-uploader .el-upload { | |
border: 1px dashed #d9d9d9; | |
border-radius: 6px; | |
cursor: pointer; | |
position: relative; | |
overflow: hidden; | |
} | |
.avatar-uploader .el-upload:hover { | |
border-color: #409eff; | |
} | |
.avatar-uploader-icon { | |
font-size: 28px; | |
color: #8c939d; | |
width: 120px; | |
text-align: center; | |
} | |
.avatar { | |
width: 120px; | |
height: 120px; | |
display: block; | |
} | |
</style> |
使用
/*导入组件*/ | |
import uploadImg from '@/components/uploadImg' | |
/*组件注册*/ | |
export default { | |
components: { uploadImg }, | |
data(){ | |
imgpath: '', | |
}, | |
methods:{ | |
/*执行uploadImg组件报出来的事件,path就是显示图片的路径*/ | |
setCardPic(path, pic) { | |
this.form[pic] = path | |
}, | |
/*详情的时候设定显示图片的路径 setEditImg是uploadImg组件提供的方法 imgpath是子组件的ref属性(看使用的组件)*/ | |
this.$refs.imgpath.setEditImg('') | |
} | |
} | |
<template> | |
<el-form-item label="广告图片:" prop="imgpath"> | |
<uploadImg @setCardPic="setCardPic($event,'imgpath')" ref="imgpath"></uploadImg> | |
<span style="font-size: 12px;color: #606266;">只能上传jpg/png/jpeg文件,且不超过4MB</span> | |
</el-form-item> | |
</template> |
效果:
el-upload组件封装后更好用了
对el-upload进行了简单的二次封装,实现了图片上传后回显的预览大图和移除图片。
组件截图
图片上传
图片的回显和操作
组件代码部分
<template> | |
<div class="component-upload-image"> | |
<el-upload | |
:action="uploadImgUrl" | |
list-type="picture-card" | |
:on-success="handleUploadSuccess" | |
:before-upload="handleBeforeUpload" | |
:on-error="handleUploadError" | |
name="file" | |
:show-file-list="false" | |
:headers="headers" | |
style="display: inline-block; vertical-align: top" | |
> | |
<el-image v-if="!value" :src="value"> | |
<div slot="error" class="image-slot"> | |
<i class="el-icon-plus" /> | |
</div> | |
</el-image> | |
<div v-else class="image"> | |
<el-image :src="value" :style="`width:150px;height:150px;`" fit="fill"/> | |
<div class="mask"> | |
<div class="actions"> | |
<span title="预览" @click.stop="dialogVisible = true"> | |
<i class="el-icon-zoom-in" /> | |
</span> | |
<span title="移除" @click.stop="removeImage"> | |
<i class="el-icon-delete" /> | |
</span> | |
</div> | |
</div> | |
</div> | |
</el-upload> | |
<el-dialog :visible.sync="dialogVisible" title="预览" width="800" append-to-body> | |
<img :src="value" style="display: block; max-width: 100%; margin: 0 auto;"> | |
</el-dialog> | |
</div> | |
</template> | |
<script> | |
import { getToken } from "@/utils/auth"; | |
export default { | |
name:'ImageUpload', | |
data() { | |
return { | |
dialogVisible: false, | |
uploadImgUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 上传的图片服务器地址 | |
headers: { | |
Authorization: "Bearer " + getToken(), | |
}, | |
}; | |
}, | |
props: { | |
value: { | |
type: String, | |
default: "", | |
}, | |
}, | |
methods: { | |
removeImage() { | |
this.$emit("input", ""); | |
}, | |
handleUploadSuccess(res) { | |
this.$emit("input", res.url); | |
this.loading.close(); | |
}, | |
handleBeforeUpload() { | |
this.loading = this.$loading({ | |
lock: true, | |
text: "上传中", | |
spinner: 'el-icon-loading', | |
background: "rgba(0, 0, 0, 0.5)", | |
customClass:'customClass' | |
}); | |
}, | |
handleUploadError() { | |
this.$message({ | |
type: "error", | |
message: "上传失败", | |
}); | |
this.loading.close(); | |
}, | |
}, | |
watch: {}, | |
}; | |
</script> | |
<style scoped lang="scss"> | |
.image { | |
position: relative; | |
.mask { | |
opacity: 0; | |
position: absolute; | |
top: 0; | |
width: 100%; | |
background-color: rgba(0, 0, 0, 0.5); | |
transition: all 0.3s; | |
} | |
&:hover .mask { | |
opacity: 1; | |
} | |
} | |
</style> |
引入组件试试吧~