近期表单写的比较多,设计到上传图片和上传文件,总结了一下,一起分享

主要功能

  • 限制图片数量
  • 限制图片宽高
  • 上传按钮展示/隐藏

父组件主要代码

html代码

<UploadImage
   ref="uploadImageRef"
   :limit-image-info="limitImageInfo"
    @uploadImage="uploadImage"
 ></UploadImage>

js代码

<script setup>
import { ref } from 'vue'
import { UploadImage } from '@/widgets/index.js' //子组件路径
// 图片操作
const limitImageInfo = ref({
  maxWidth: 820,//上传图片最大宽度
  maxHeight: 608,//上传图片最大高度
  imageNum: 5,//上传图片最大数量
  limitImageSize: true,//是否限制图片宽高
})
const uploadImageRef = ref(null)//稍后再看这个的作用
let picListArr = ref([])//子组件返回的数据,主要用于父组件里前端和后端交互使用
const uploadImage = (e) => {
  picListArr.value = e
}
</script>

子组件主要代码

html代码
isShowUpload:上传按钮显示状态
handleUploadImage:上传事件
delImage:删除事件

<template>
  <div class="upload-license-left">
    <div v-if="isShowUpload" class="left-images left-images-up">
      <div class="left-images-input">
        <input
          id="uploadimage"
          type="file"
          accept="image/png, image/jpeg, image/jpg"
          @change="handleUploadImage"
        />
      </div>
    </div>
    <template v-if="pic.length">
      <div v-for="(item, index) in pic" :key="index" class="left-images-img">
        <img :src="item" alt="" />
        <img
          class="close-btn"
          src="@/pages/qyneed/need-fill/images/close.png"
          alt=""
          @click="delImage(index)"
        />
      </div>
    </template>
  </div>
</template>

js代码

<script setup>
import { ref, computed, watch } from 'vue'

import { DialogModel } from '@/components' //封装的弹窗组件,这里不再展示
import { limitImageSize } from './help' //上传图片的限制条件
const { fetchPicUpload } = FileHandle() //图片的处理逻辑
const props = defineProps({
//父组件传递的参数
  limitImageInfo: {
    type: Object,
    default: () => {
      return {}
    },
  },
})
const tempValue = ref(props.limitImageInfo)
//如果不computed传递的数据是空
const showLimitImageInfo = computed(() => {
  return tempValue.value
})
// eslint-disable-next-line no-console
console.log(showLimitImageInfo.value)
// 上传图片
let pic = ref([])
let picListArr = ref([])
const emits = defineEmits(['uploadImage'])
const handleUploadImage = async (e) => {
  showLimitImageInfo.value.limitImageSize &&
    (await limitImageSize(
      e,
      showLimitImageInfo.value.maxWidth,
      showLimitImageInfo.value.maxHeight
    ))
  if (picListArr.value.length >= showLimitImageInfo.value.imageNum) {
    DialogModel({
      message: `最多可以添加${showLimitImageInfo.value.imageNum}张图片!`,
      cancelable: false,
      confirm: fialComfilmBtn,
    })
  } else {
    const file = e.target.files[0]
    let picObj = await fetchPicUpload(file)
    if (picObj) {
      pic.value.push(fileToDataurl(file))
      picListArr.value.push(picObj.path)
    }
  }
  emits('uploadImage', picListArr.value)
}
// 文件转化成url
const fileToDataurl = (file) => {
  return URL.createObjectURL(file)
}
// 删除图片
const delImage = (index) => {
  pic.value.splice(index, 1)
  picListArr.value.splice(index, 1)
}
//vue3将变量导出,供父组件使用
defineExpose({
  pic,
})
const isShowUpload = ref(true)
watch(
  () => picListArr.value,
  () => {
    if (picListArr.value.length >= showLimitImageInfo.value.imageNum) {
      isShowUpload.value = false
    } else {
      isShowUpload.value = true
    }
  },
  { deep: true }
)
const fialComfilmBtn = () => {}
</script>

css主要代码

<style scoped>
#uploadimage {
  height: 100%;
  cursor: pointer;
}
.upload-license-left {
  display: flex;
  flex-wrap: wrap;
}
.left-images-up {
  width: 120px;
  height: 120px;
  background-image: url('@/pages/qyneed/need-fill/images/uploadIcon.png');
  background-size: 100% 100%;
  /* margin-bottom: 20px; */
  margin-right: 20px;
}
.left-images-input {
  width: 100%;
  height: 100%;
  position: relative;
}
.left-images-input input {
  width: 100%;
  height: 100%;
  cursor: pointer;
  opacity: 0;
}

.left-images-img {
  width: 120px;
  height: 120px;
  background: #f2f2f2;
  position: relative;
  margin-right: 20px;
  margin-bottom: 20px;
}
.left-images-img img:first-child {
  width: 120px;
  height: 120px;
  position: absolute;
  top: 0;
  left: 0;
  border-radius: 10px;
}
.left-images-img img.close-btn {
  width: 24px;
  height: 24px;
  position: absolute;
  top: -12px;
  right: -12px;
  cursor: pointer;
}
</style>

help.js里limitImageSize 方法

import { DialogModel } from '@/components/index.js'

let limitImageSize = (e, width, height) => {
  return new Promise((resolve, reject) => {
    let url = window.URL || window.webkitURL
    let img = new Image()
    img.src = url.createObjectURL(e.target.files[0])
    let status = 0
    img.onload = () => {
      if (img.width > width) {
        DialogModel({
          message: `图片宽度不能超过${width}`,
          cancelable: false,
          confirm: fialComfilmBtn,
        })
        reject(false)
      } else if (img.height > height) {
        DialogModel({
          message: `图片高度不能超过${height}`,
          cancelable: false,
          confirm: fialComfilmBtn,
        })
        reject(false)
      } else {
        resolve(true)
      }
    }
  })
}
const fialComfilmBtn = () => {}
export { limitImageSize }

上传文件及文件格式快速通道

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐