vue3上传组件封装

284 阅读2分钟

上传组件封装 - 单独使用接口请求

前期准备工作

  1. 首先准备好上传接口

    请求头一般要把类型改成form-data,还有就是请求头的token了,这里我在axios封装的时候就已经加过了

    uploadImg: (data: any) =>
     http.post(`/system/files/upload`, data, { headers: { 'Content-Type':  'multipart/form-data' } }),
     
    
  2. 下面直接上组件封装部分

`

<script lang="ts" setup>
import { ref, watch } from 'vue'
import { Plus, ZoomIn, Delete } from '@element-plus/icons-vue'
import { ElMessage, ElLoading, type UploadProps } from 'element-plus'
import userService from '@/commons/request'

interface Props {
  imageUrl?: string // 回显图片地址
  action?: string //   上传地址
  imgText?: string //   文字可以不传
  imgUpText?: string // 上传按钮的文字
  disabledType?: boolean // 是否禁用上传
}
const props = withDefaults(defineProps<Props>(), {
  imageUrl: '',
  action: '/activity/resource/uploadFile',
  imgText: '支持jpg/jpeg/png;文件大小不能超过2M;封面图建议尺寸940px*400px',
  imgUpText: '上传封面',
  disabledType: false,
})

const imagesURL = ref<string>(props.imageUrl)
const emits = defineEmits(['imgSuccess', 'imgDelete'])
const disabled = ref<boolean>(props.imageUrl ? true : false)
const handleChange = (file: any, fileList: any) => {
  console.log(file)
  console.log(fileList)
  let rawFile = file.raw
  if (
    rawFile.type !== 'image/jpeg' &&
    rawFile.type !== 'image/png' &&
    rawFile.type !== 'image/jpg'
  ) {
    ElMessage.error('仅支持格式为jpg, jpeg, png的图片')
    return false
  } else if (rawFile.size / 1024 / 1024 > 2) {
    ElMessage.error('图片文件大小不能超过2MB!')
    return false
  } else {
    let formData = new FormData()
    formData.append('file', rawFile)
    // formData.append('fileType', '1') // 1:图片 2:视频 3:音频 4:文档
    const loadingInstance = ElLoading.service({
      text: '正在上传',
      background: 'rgba(0,0,0,.2)',
    })
    // 请求接口上传图片到服务器
    userService.uploadImg(formData).then((res: any) => {
      console.log(res)
      if (res) {
        loadingInstance.close()
        let obj = {
          imgUrl: res.url,
        }
        emits('imgSuccess', obj)
        imagesURL.value = res
      } else {
        loadingInstance.close()
        ElMessage.warning(`文件上传失败`)
      }
    })
  }
  return true
}

const dialogVisible = ref(false)

const handlePictureCardPreview: UploadProps['onPreview'] = ($event: any) => {
  $event.stopPropagation()
  dialogVisible.value = true
}

const handlePictureCardDelete: UploadProps['onRemove'] = ($event: any) => {
  // 禁止冒泡
  $event.stopPropagation()
  imagesURL.value = ''
  emits('imgDelete', '')
  disabled.value = false
  return false
}

watch(
  () => props.imageUrl,
  () => {
    imagesURL.value = props.imageUrl
  },
)
</script>

<style lang="scss" scoped>
:deep().avatar-uploader {
  .avatar {
    width: 300px;
    height: 204px;
    display: block;
  }
  .el-upload {
    border: 1px dashed #dcdfe6;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    transition: 0.2s;
    background: rgba(0, 0, 0, 0.04) !important;
  }

  .el-upload:hover {
    border-color: #14b194;
  }
}
.el-icon.avatar-uploader-icon {
  font-size: 32px;
  color: rgba(0, 0, 0, 0.45);
  text-align: center;
}

.upImgBox {
  width: 300px;
  height: 204px;
  font-size: 14px;
  font-family:
    PingFangSC-Regular,
    PingFang SC;
  font-weight: 400;
  color: rgba(0, 0, 0, 0.65);
  text-align: center;
  padding-top: 24px;
  box-sizing: border-box;
}

.up-img-text {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
.upImgText {
  font-size: 14px;
  color: rgba(0, 0, 0, 0.6);
  margin-top: 4px;
}

.avatar-img-wrapper {
  position: relative;
  display: inline-block;
  width: 300px;
  height: 204px;
  border-radius: 6px;
  overflow: hidden;
  background: rgba(0, 0, 0, 0.04) !important;
}
.icon-group-marker {
  position: absolute;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
  cursor: default;
  display: inline-flex;
  justify-content: center;
  align-items: center;
  color: #fff;
  opacity: 0;
  font-size: 20px;
  background-color: var(--el-overlay-color-lighter);
  transition: opacity var(--el-transition-duration);
}

.icon-group-marker:hover {
  opacity: 1;
}

.avatar-preview-icon {
  font-size: 32px;
  color: rgba(255, 255, 255, 0.85);
  cursor: pointer;
}
.avatar-delete-icon {
  margin-left: 20px;
  font-size: 32px;
  color: rgba(255, 255, 255, 0.85);
  cursor: pointer;
}
</style>

效果图

上传前 上传前.png

上传后 上传后.png

鼠标滑过 鼠标滑过.png

预览 预览.png