系统搭建五---------图片上传组件

140 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情

element plus的el-upload的二次封装

没什么难的,感觉分开说的话也没什么,就直接贴出整体代码啦,注释应该是比较详细的,特别注意点的话,就在下面解释,有耐心的话可以看看

<template>
  <div>
    <!-- 图片上传组件 :on-change='picChange'  :http-request="upload"-->
    <el-upload
      :class="{ hide: isShowUpload }"
      :disabled="disabled"
      :limit="limits"
      :action="uploadUrl"
      list-type="picture-card"
      v-model:file-list="imgs"
      :on-success="handleAvatarSuccess"
      :on-preview="watchPic"
      :on-error="imgUploadError"
      :on-remove="picRemove"
      :on-exceed="picExceed"
      :before-upload="beforeUpload"
      :data="upLoadData"
      name="image"
    >
      <!-- :class="{ hide: isShowUploadPic }" -->
      <div class="icon">
        <el-icon><CameraFilled /></el-icon>
        上传图片
      </div>
    </el-upload>
    <!-- 图片展示的弹层 -->
    <el-dialog v-model="showDialog">
      <el-image :src="dialogImageUrl" fit="cover" />
    </el-dialog>
  </div>
</template>

<script setup name="imgUpload">
import { ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { CameraFilled } from '@element-plus/icons-vue'

const isShowUpload = ref(false)
// props
const props = defineProps({
  // 图片开始默认的值
  imgs: {
    type: Array,
    default: () => []
  },
  // 上传类型
  imgType: {
    type: Array,
    default: () => [
      'image/jpeg',
      'image/jpg',
      'image/png',
      'image/gif',
      'image/bmp'
    ]
  },
  // 上传大小
  maxSize: {
    type: Number,
    // 2 * 1024 * 1024 2M
    default: 2097152
  },
  // 是否禁用
  disabled: {
    type: Boolean,
    default: false
  },
  // 最大上传数量
  limits: {
    type: Number,
    default: 1
  },
  // 上传的url
  uploadUrl: {
    type: String,
    default:
      import.meta.env.VITE_NODE_ENV === 'development'
        ? 'https://zyjy-dev.51jshl.com/api/common/upload'
        : '/api/common/upload'
  },
  // 上传时附带的额外参数
  upLoadData: {
    type: Object,
    default: function () {
      return { category: 'school_image' }
    }
  }
})

// emits
const emits = defineEmits(['ossImgUrl'])

// 编辑时 无法修改 props 的imgs,这样进行改变,本来使用 v-model 的,但有点别的原因不这么做啦
let imgList = props.imgs

// 控制显示弹层
let showDialog = ref(false)
// 弹层展示的 预览图片
let dialogImageUrl = ref()

// 展示图片的文件
const watchPic = (file) => {
  showDialog.value = true
  dialogImageUrl.value = file.url
}
// 移除文件列表 文件列表移除文件时的钩子
const picRemove = (file, filelist) => {
  imgList = filelist
  isShowUpload.value = imgList.length >= props.limits
}
// 图片上传成功
const handleAvatarSuccess = async (res, file) => {
  if (res.code === 200) {
    imgList.push({ url: res.data })
    emits('ossImgUrl', imgList)
    isShowUpload.value = imgList.length >= props.limits
  }
}
// 图片上传失败
const imgUploadError = (err, file, fileList) => {
  ElMessage.error('图片上传失败')
  return false
}
// 当超出限制时,执行的钩子函数
const picExceed = (file, fileList) => {
  ElMessage.error(`上传图片最大数量为${props.limits}`)
}
// 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用 这里只是使用超过最大上传数量,隐藏上传组件
// function picChange(file, fileList) {
//   isShowUpload.value = fileList.length >= props.limits
//   console.log(isShowUpload.value)
// }
// 上传文件之前进行限制 例如文件类型和大小
function beforeUpload(file) {
  // console.log(file)
  // console.log(props.imgType.includes(file.type))
  if (!props.imgType.includes(file.type)) {
    ElMessage.error('上传的图片类型只能是JPG、PNG、JPEG的类型')
    return false
  }
  if (file.size > props.maxSize) {
    // console.log(file.size)
    ElMessage.error('最大上传大小是2M')
    return false
  }
  return true
}

// let ossConfigure = reactive()
// onMounted
onMounted(async () => {
  // 编辑时一进来就判断一下是否显示上传
  isShowUpload.value = props.imgs.length >= props.limits
})
// 覆盖默认的上传行为
async function upload(params) {
  // console.log(params, '覆盖默认的上传行为')
// 这里我本来要这样写的,后面没有,可以不用这个
}
</script>

<style scoped lang="scss">
 // 这里的为了超出限制的上传数量,也就是limits的话,隐藏上传显示
::v-deep .hide {
  .el-upload--picture-card {
    display: none;
    transition: 0.3s;
  }
}
.icon {
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  align-items: center;
  color: #999;
}
</style>
  1. on-preview: 点击文件列表中已上传的文件时的钩子 =》 点击显示大图
  2. on-remove: 文件列表移除文件时的钩子 =》 更新当前的图片
  3. on-success: 文件上传成功时的钩子 =》通过 emits 改变父组件绑定的值
  4. on-error: 文件上传失败时的钩 =》 提示一下
  5. on-exceed: 当超出限制时,执行的钩子函数
  6. before-upload: 上传文件之前的钩子,参数为上传的文件, 若返回false或者返回 Promise 且被 reject,则停止上传。=> 上传之间判断一下上传文件类型,大小,长宽等进行一下限制

给el-upload添加css,根据当前上传张数动态使其显示

1. 首先el-upload里面绑定一个占位class:
<el-upload  :on-remove="picRemove" :on-change="picChange" :class="{hide:isShowUpload}" />
2. isShowUpload 的初始值:
const isShowUpload = ref(false)
3.onMounted里面(vue的生命周期,因为编辑的话会触发,我在外面也写了一个,看代码里面的注释):
 isShowUpload.value = fileList.length >= props.limits
4. handleRemove里面(删除文件被调用的那个):
 fileList = filelist
  isShowUpload.value = fileList.length >= props.limits
5. 在style里面加上
<style scoped lang="scss">
::v-deep .hide {
  .el-upload--picture-card {
    display: none;
    transition: 0.5s;
  }
}
</style>