pc端封装upload组件

在我们日常的开发工作中时长会用到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>

第五步:在父组件中使用:

  1. 先引入组件进来

import PicUpload from '@/components/pic-upload'
  1. components中定义

components: { PicUpload },
  1. 在页面中使用

 <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>

最终效果:

猜你喜欢

转载自blog.csdn.net/m0_71225058/article/details/129687073