Vue upload image component

Upload image component

Introduction

The uploading picture component is also one of the most important basic components of the background management system. This function supports picture file type checking, picture size checking, picture resolution checking and picture ratio checking and other functions.

Mainly rely on instructions (install first, steps omitted)

 {
    
    
    "element-ui": "2.11.1",  
    "vue": "^2.6.10",
    "vue-router": "^3.0.1"
 }

text

1. Components

src/components/Upload.vue

<template>
  <div class="custom-upload">
    <input
      :id="id"
      type="file"
      style="display: none"
      name="single"
      accept="image/*"
      @change="onChange"
    />
    <el-button size="small" type="primary" :loading="loading" @click="handleOpenFile">
      <i class="fa fa-upload" />
      添加图片
    </el-button>
    <div v-if="tips" class="tips clear-margin-top">{
   
   { tips }}</div>
  </div>
</template>

<script>
// 上传文件组件
import {
     
     
  isAppropriateResolution,
  isAppRatio,
  isImageFile,
  isMaxFileSize
} from '@/utils/upload'    // upload.js 文件见下文

// 定义的接口根据自己项目更换
import {
     
      uploadImage } from '@/api/upload'  

import {
     
      Message } from 'element-ui'

export default {
     
     
  name:'Upload',
  props: {
     
     
    // 最大上传文件的大小 单位(MB)
    maxFileSize: {
     
     
      type: Number,
      default: 2
    },
    // 提示内容
    tips: {
     
     
      type: String
    },
    // 图片文件分辨率的宽度
    width: {
     
     
      type: Number,
      width: 460
    },
    // 图片文件分辨率的高度
    height: {
     
     
      type: Number,
      default: 300
    },
    // 是否限制分辨率
    isResolution: {
     
     
      type: Boolean,
      default: false
    },
    // 是否限制比列
    isRatio: {
     
     
      type: Boolean,
      default: false
    },
    // 比列 ag: 1:1 时给 [1,1]
    ratio: {
     
     
      type: Array
    }
  },
  data() {
     
     
    return {
     
     
      id: 'upload-input-' + +new Date(),
      loading: false
    }
  },

  methods: {
     
     
    // 打开文件
    handleOpenFile() {
     
     
      const input = document.getElementById(this.id)
      // 解决同一个文件不能监听的问题
      input.addEventListener(
        'click',
        function() {
     
     
          this.value = ''
        },
        false
      )
      // 点击input
      input.click()
    },

    // 选择好文件
    async onChange($event) {
     
     
      this.loading = true
      const file = $event.target.files[0]
      if (!file) {
     
     
        this.loading = false
        return Message.error('选择图片失败')
      }

      // 限制为图片文件
      if (!isImageFile(file)) {
     
     
        this.loading = false
        return
      }

      // 限制文件上传大小
      if (!isMaxFileSize(file, this.maxFileSize)) {
     
     
        this.loading = false
        return
      }

      try {
     
     
        // 限制分辨率
        if (this.width !== 0 && this.height !== 0 && this.isResolution) {
     
     
          await isAppropriateResolution(file, {
     
     
            width: this.width,
            height: this.height
          })
        }

        // 限制比列
        if (this.isRatio && this.ratio && this.ratio.length === 2) {
     
     
          await isAppRatio(file, this.ratio)
        }
        // 开始上传
        this.upload(file)
      } catch (error) {
     
     
        Message.error(error.message || '上传失败')
        console.log(error)
        this.loading = false
      }
    },

    // 自定义上传
    async upload(file) {
     
     
      try {
     
     
        const res = await uploadImage(file)
        this.$emit('subUploadSucceed', res)
        Message.success('上传成功')
        this.loading = false
      } catch (error) {
     
     
        this.loading = false
        console.log(error)
        Message.error(error.message || '上传失败')
      }
    }
  }
}
</script>

<style lang="scss"  scoped >
.custom-upload {
     
     
  .tips {
     
     
    margin-top: 10px;
    color: red;
    font-size: 12px;
  }
  .clear-margin-top {
     
     
    margin-top: 0;
  }
}
</style>

2. Use

<template>
  <div>
    <app-upload
      tips="请上传720*294的图片"
      :is-resolution="true"
      :width="720"
      :height="294"
      @subUploadSucceed="handleUploadSucceed"
    />
    <img v-if="url" :src="url" class="image-size" />
  </div>
</template>

<script>
import AppUpload from '@/components/Upload'
export default {
     
     
  name: 'Banner',
  components: {
     
     
    AppUpload
  },
  data() {
     
     
    return {
     
     
      url: ''
    }
  },
  methods: {
     
     
    // 海报上传成功
    handleUploadSucceed(url) {
     
     
      this.url = url
    }
  }
}
</script>

<style rel="stylesheet/scss" lang="scss" scoped>
.image-size {
     
     
  margin-top: 10px;
  width: 150px;
  height: 92px;
  cursor: pointer;
}
</style>

3. Supplement src/utils/upload.js file

import {
    
     Message } from 'element-ui'

/**
 *
 * @param {file} file 源文件
 * @desc 限制为图片文件
 * @retutn 是图片文件返回true否则返回false
 */
export const isImageFile = (file,fileTypes) => {
    
    
  const types =fileTypes|| [
    'image/png',
    'image/gif',
    'image/jpeg',
    'image/jpg',
    'image/bmp',
    'image/x-icon'
  ]
  const isImage = types.includes(file.type)
  if (!isImage) {
    
    
    Message.error('上传文件非图片格式!')
    return false
  }

  return true
}

/**
 *
 * @param {file} file 源文件
 * @param {number} fileMaxSize  图片限制大小单位(MB)
 * @desc 限制为文件上传大小
 * @retutn 在限制内返回true否则返回false
 */
export const isMaxFileSize = (file, fileMaxSize = 2) => {
    
    
  const isMaxSize = file.size / 1024 / 1024 < fileMaxSize
  if (!isMaxSize) {
    
    
    Message.error('上传头像图片大小不能超过 ' + fileMaxSize + 'MB!')
    return false
  }
  return true
}

/**
 *
 * @param {file} file 源文件
 * @desc 读取图片文件为base64文件格式
 * @retutn 返回base64文件
 */
export const readFile = file => {
    
    
  return new Promise((resolve, reject) => {
    
    
    const reader = new FileReader()
    reader.onload = e => {
    
    
      const data = e.target.result
      resolve(data)
    }
    reader.onerror = () => {
    
    
      const err = new Error('读取图片失败')
      reject(err.message)
    }

    reader.readAsDataURL(file)
  })
}

/**
 *
 * @param {string} src  图片地址
 * @desc 加载真实图片
 * @return 读取成功返回图片真实宽高对象 ag: {width:100,height:100}
 */
export const loadImage = src => {
    
    
  return new Promise((resolve, reject) => {
    
    
    const image = new Image()
    image.src = src
    image.onload = () => {
    
    
      const data = {
    
    
        width: image.width,
        height: image.height
      }
      resolve(data)
    }
    image.onerror = () => {
    
    
      const err = new Error('加载图片失败')
      reject(err)
    }
  })
}

/**
 *
 * @param {file} file 源文件
 * @param {object} props   文件分辨率的宽和高   ag: props={width:100, height :100}
 * @desc  判断图片文件的分辨率是否在限定范围之内
 * @throw  分辨率不在限定范围之内则抛出异常
 *
 */
export const isAppropriateResolution = async(file, props) => {
    
    
  try {
    
    
    const {
    
     width, height } = props
    const base64 = await readFile(file)
    const image = await loadImage(base64)
    if (image.width !== width || image.height !== height) {
    
    
      throw new Error('上传图片的分辨率必须为' + width + '*' + height)
    }
  } catch (error) {
    
    
    throw error
  }
}

/**
 *
 * @param {file} file 源文件
 * @param {array} ratio   限制的文件比例 ag:  ratio= [1,1]
 * @desc 判断图片文件的比列是否在限定范围
 * @throw  比例不在限定范围之内则抛出异常
 */
export const isAppRatio = async(file, ratio) => {
    
    
  try {
    
    
    const [w, h] = ratio
    if (h === 0 || w === 0) {
    
    
      const err = '上传图片的比例不能出现0'
      Message.error(err)
      throw new Error(err)
    }
    const base64 = await readFile(file)
    const image = await loadImage(base64)
    if (image.width / image.height !== w / h) {
    
    
      throw new Error('上传图片的宽高比例必须为 ' + w + ' : ' + h)
    }
  } catch (error) {
    
    
    throw error
  }
}

Guess you like

Origin blog.csdn.net/qq_39953537/article/details/99963477