写在前面
- 本文技术栈基于Vue2+ElementUi+Axios+Less
- 文件上传在日常开发中也是非常常见,本文会基于实际项目的需求从0到1手把手带你基于el-upload封装一个文件上传组件,同时介绍一些需要注意的细节
组件的一些功能功能点
- 选取文件时自动上传文件,即
auto-upload=true
这也是默认值;特别指出这个属性也是因为当此属性设置为false
时需要手动触发上传函数,逻辑与自动上传处理时存在差异 - 下面栗子以图片上传为例,只允许上传一张,并且文件上传成功后展示图片文件的同时隐藏上传组件,在清空上传内容时再重新展示组件(因此这么做的话on-exceed函数也就不再需要了)
- 需要上传文件的预览、删除以及数据回显,值得一提的是预览和删除功能逻辑组件已经内置了;但是预览我们需要考虑的是样式问题以及不同文件的预览,例如图片,音视频等等
例子准备
- 根据上面的需求,先找到对应的组件demo栗子,如下:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e118c13d8e225e416915f3729aa97aca.png)
自定义参数以及钩子函数
- 当然,除了原有栗子,想要实现上述功能点的话,还需要添加额外的钩子函数以及属性,例子如下,根据需要设置一些属性和钩子函数,用于处理逻辑
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/778844e6fe5fbfc6994f1c2bb0bed487.png)
- 关键的上传钩子:文件上传前的格式校验,填充额外的请求参数;文件上传成功的钩子,能够拿到接口返回的参数
handleBeforeUpload(file) {
const suffix = file.name?.slice(file.name?.lastIndexOf('.') + 1)
const reg = /jpe?g|png/i
if (!reg.test(suffix)) {
this.$message.warning('仅支持jpg、jpeg、png格式的图片!')
return false
}
this.fileListData.unitId = id;
this.fileListData.name = name;
}
handleSuccess(response) {
this.$message.success('上传成功!')
},
请求栗子
- 根据上面的描述,以图片上传为例执行一个上传请求
- 可以看到请求体的参数默认为FormData格式,
file
属性对应的参数就是上传的文件内容,其他参数是根据需求咱们自己添加的,即上面提到的参数 data
绑定的对象
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/8a400115b6523c61318b348e132e3d8e.png)
- 可以看到文件上传成功后,上传组件依旧存在,但是一开始说过这里文件限制上传一个,所以这里的处理是上传成功之后隐藏上传组件;而不是等用户上传第二个时提示他只能上传一个,从而浪费时间进行无意义的操作
- 隐藏组件的话通过样式简单控制就行,需要注意的时需要用到属性透传(不建议使用全局样式或是通过
!import
等方式去处理,容易造成全局样式污染!!!),我这v2项目是用/deep/
,例如v3用的就是:deep()
,根据自己情况使用,样式代码如下:
<style lang="less" scoped>
.hideUpload /deep/ .el-upload--picture-card {
display: none;
}
</style>
- 组件通过
:class
动态绑定类名,也就是hideUpload
;接着通过自定义isHideUplaod属性(它是一个布尔值)来控制类名样式是否应用
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/5d5612964ec095421834475c3c3bd49d.png)
- 那么效果就会变成这样
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/320dc753e264f9649b7b3505ba382709.png)
完整代码
- 组件名字这里定义为 UploadPhotoFile
<template>
<div>
<el-upload
class="upload-cover"
drag
list-type="picture-card"
:class="{ hideUpload: isHideUplaod }"
:action="uploadUrl"
:limit="1"
:file-list="fileList"
:on-success="handleSuccess"
:before-upload="handleBeforeUpload"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
:data="otherReqParams"
>
<div class="up-tip" >
<div class="el-upload__text">
<span>点击或将文件拖拽到这里上传</span>
</div>
</div>
<div class="el-upload__tip" slot="tip">
格式:支持jpg、jpeg、png;尺寸:750px*420px;限1M以内只可上传一张
</div>
</el-upload>
<el-dialog :visible.sync="imgConfig.dialogVisible">
<img width="100%" :src="imgConfig.dialogImageUrl" alt="">
</el-dialog>
</div>
</template>
<script>
export default {
props: {
reqParams: {
type: Object,
default: () => {}
},
fileList: {
type: Array,
default: () => []
}
},
data() {
return {
uploadUrl: "",
otherReqParams: {
fileType: 1,
multipartFile: {}
},
imgConfig: {
dialogVisible: false,
dialogImageUrl: ''
},
isHideUplaod: false,
}
},
created() {
this.uploadUrl = 'xxxx'
},
methods: {
handleRemove() {
this.isHideUplaod = false
},
handlePictureCardPreview(file) {
this.imgConfig.dialogImageUrl = file.url;
this.imgConfig.dialogVisible = true;
},
handleSuccess(response) {
this.isHideUplaod = true
this.$message.success('上传成功!')
},
handleBeforeUpload(file) {
const suffix = file.name?.slice(file.name?.lastIndexOf('.') + 1)
const reg = /jpe?g|png/i
if (!reg.test(suffix)) {
this.$message.warning('仅支持jpg、jpeg、png格式的图片!')
return false
}
this.otherReqParams.unitId = unitId;
this.otherReqParams.loginName = loginName;
}
}
}
</script>
<style lang="less" scoped>
.hideUpload /deep/ .el-upload--picture-card {
display: none;
}
// 其他的一些样式控制,根据情况自定义
.upload-cover /deep/ .up-tip{
height: 128px;
line-height: 128px;
img {
height: 30px;
}
.el-upload__text {
position: absolute;
top: 28px;
left: 50%;
transform: translateX(-50%);
font-size: 12px;
}
}
.upload-cover /deep/ .el-upload-dragger {
width: 341px;
height: 148px;
}
.upload-cover /deep/ .el-upload__tip {
color: #a7a3a3;
}
</style>
<template>
<div>
<UploadPhotoFile :fileList="fileList"></UploadPhotoFile>
</div>
</template>
// 导入组件
import UploadPhotoFile from './components/UploadPhotoFile.vue'
export default {
components: {
UploadPhotoFile
},
data() {
return {
fileList: [], //传入回显数组,格式为 {name: string, url: string}[]
}
},
}
写在最后
- 以上就是以图片上传为例子,基于el-upload组件进行二次封装,结合了该组件的一些可选参数以及钩子函数还有样式透传去封装一个符合业务需求的文件上传组件;
- 除此之外,在开发过程中当
auto-upload=false
即手动上传时,需要处理的情况也不一样;官方文档中有许多栗子,根据不同需求选择对应的模板组件去改造;以及上传的文件是音视频文件时,预览过程中会需要用到 video, audio
等; - 最后,以上就是本文所有内容了,希望对你能有所帮助或是启发☀☀☀