vue上传图片组件

上传图片组件

简介

上传图片组件也是后台管理系统的最重要的基础组件之一,这里功能支持图片文件类型检验,图片大小检验,图片分辨率校验以及图片比列校验等功能。

主要依赖说明 (先安装,步骤略)

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

正文

1.组件

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.使用

<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.补充src/utils/upload.js 文件

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

猜你喜欢

转载自blog.csdn.net/qq_39953537/article/details/99963477