基于el-upload实现文件上传组件封装以及细节处理

写在前面

  • 本文技术栈基于Vue2+ElementUi+Axios+Less
  • 文件上传在日常开发中也是非常常见,本文会基于实际项目的需求从0到1手把手带你基于el-upload封装一个文件上传组件,同时介绍一些需要注意的细节

组件的一些功能功能点

  • 选取文件时自动上传文件,即auto-upload=true这也是默认值;特别指出这个属性也是因为当此属性设置为false时需要手动触发上传函数,逻辑与自动上传处理时存在差异
  • 下面栗子以图片上传为例,只允许上传一张,并且文件上传成功后展示图片文件的同时隐藏上传组件,在清空上传内容时再重新展示组件(因此这么做的话on-exceed函数也就不再需要了)
  • 需要上传文件的预览、删除以及数据回显,值得一提的是预览和删除功能逻辑组件已经内置了;但是预览我们需要考虑的是样式问题以及不同文件的预览,例如图片,音视频等等

例子准备

  • 根据上面的需求,先找到对应的组件demo栗子,如下:
  • 基于el-upload实现文件上传组件封装以及细节处理_第1张图片

自定义参数以及钩子函数

  • 当然,除了原有栗子,想要实现上述功能点的话,还需要添加额外的钩子函数以及属性,例子如下,根据需要设置一些属性和钩子函数,用于处理逻辑
    基于el-upload实现文件上传组件封装以及细节处理_第2张图片
  • 关键的上传钩子:文件上传前的格式校验,填充额外的请求参数;文件上传成功的钩子,能够拿到接口返回的参数
// 文件上传前的钩子
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
   }
   // 上传的额外参数,例如id,name等等,根据情况有需要的话添加
   this.fileListData.unitId = id;
   this.fileListData.name = name;
 }
// 文件上传成功,接受一个返回对象
 handleSuccess(response) {
    // TODO 根据返回的response对象,进行自己想要的操作,例如属性赋值等等
    this.$message.success('上传成功!')
  },

请求栗子

  • 根据上面的描述,以图片上传为例执行一个上传请求
  • 可以看到请求体的参数默认为FormData格式,file 属性对应的参数就是上传的文件内容,其他参数是根据需求咱们自己添加的,即上面提到的参数 data 绑定的对象
    基于el-upload实现文件上传组件封装以及细节处理_第3张图片
  • 可以看到文件上传成功后,上传组件依旧存在,但是一开始说过这里文件限制上传一个,所以这里的处理是上传成功之后隐藏上传组件;而不是等用户上传第二个时提示他只能上传一个,从而浪费时间进行无意义的操作
  • 隐藏组件的话通过样式简单控制就行,需要注意的时需要用到属性透传(不建议使用全局样式或是通过!import等方式去处理,容易造成全局样式污染!!!),我这v2项目是用/deep/,例如v3用的就是:deep(),根据自己情况使用,样式代码如下:
<style lang="less" scoped>
.hideUpload /deep/ .el-upload--picture-card {
  display: none;
}
style>
  • 组件通过 :class 动态绑定类名,也就是hideUpload;接着通过自定义isHideUplaod属性(它是一个布尔值)来控制类名样式是否应用
    基于el-upload实现文件上传组件封装以及细节处理_第4张图片
  • 那么效果就会变成这样
    基于el-upload实现文件上传组件封装以及细节处理_第5张图片

完整代码

  • 组件名字这里定义为 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: {
    // 父组件传入的请求对象,用于请求参数赋值;
    // 或者通过 $emit('xxx', params)方式将参数返回给父组件
    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等;
  • 最后,以上就是本文所有内容了,希望对你能有所帮助或是启发☀☀☀

你可能感兴趣的:(vue.js,elementui,javascript)