vue圖片上傳組件


1、正常上傳

<template>
  <div class="upload-wrapper">
    <div v-if="!imgUrl" class="noneData">
      <div @click="openLocals">
        <img src="./imgs/icon_jh.png" alt="">
        <div>上傳圖片</div>
      </div>
      <form :id="fileName+'Form'" enctype="multipart/form-data" style="display:none;">
        <input ref="pathClear" type="file"  accept="image/*" :name="fileName" @change="fileChanged"/>
      </form>
    </div>
    <div v-else class="havaData">
      <img :src="imgUrl" alt="" @click="actImg">
    </div>
  </div>
</template>
<script>
import $ from 'jquery';
import { Indicator, Toast } from 'mint-ui';
import { webPostObject } from './ossUpload/index.js';
export default {
  data() {
    return {
    };
  },
  props: {
    // file控件名稱
    fileName: {
      type: String,
      required: true
    },
    // 圖片地址
    imgUrl: {
      type: String,
      default: '',
      required: true
    },
  },
  methods: {
    // 點擊圖片
    actImg() {
      console.log('點擊圖片');
    },
    // 刪除圖片
    removePackage() {
      let _self = this;
      _self.$emit('removeImg');
    },
    // 上傳圖片
    openLocals() {
      $(`input[type='file'][name='${this.fileName}']`).click();
    },
    fileChanged() {
      this.uploadImg();
    },
    uploadImg() {
      let _self = this;
      let fileElement = $(`input[type='file'][name='${_self.fileName}']`);
      let filename = fileElement.val();
      let ext = filename.substring(filename.lastIndexOf('.')).toLowerCase();
      if (ext !== '.jpg' && ext !== '.png' && ext !== '.jpeg' && ext !== '.bmp') {
        Toast({
          message: '僅支持.jpg、.png、.jpeg、.bmp的圖片格式',
          position: 'bottom',
          duration: 2000
        });
        return false;
      }
      let file = fileElement[0].files[0];
      let imgSize = Math.ceil(file.size / 1024 / 1024);
      if (imgSize > 20) {
        Toast({
          message: '文件不能大於20MB,重新選擇文件',
          position: 'bottom',
          duration: 2000
        });
        _self.$refs.pathClear.value = '';
        return false;
      }
      Indicator.open('圖片正在上傳中...');
      // 服務器上傳
      // let formdata1 = new FormData();
      // formdata1.append('file', file, file.name);
      // let config = {
      //   headers: { 'Content-Type': 'multipart/form-data' }
      // };
      // axios.post(`${process.env.UPLOAD_HOST}`, formdata1, config).then((res) => {
      //   console.log(res);
      //   let data = res.data;
      //   Indicator.close();
      //   if (data) {
      //     _self.$emit('uploadSuccess', data[0]);
      //   }
      // }).catch(() => {
      //   Indicator.close();
      //   Toast({
      //     message: '圖片上傳失敗',
      //     position: 'bottom',
      //     duration: 2000
      //   });
      // });
      // oss web直傳
      webPostObject(file, file.name).then(data => {
        console.log('oss web直傳', data);
        Indicator.close();
        _self.$emit('uploadSuccess', data);
      }).catch(() => {
        Indicator.close();
        Toast({
          message: '圖片上傳失敗',
          position: 'bottom',
          duration: 2000
        });
      });
    },
  },
};
</script>
<style lang="less" scoped>
.upload-wrapper{
  height: 100%;
}
.noneData,.havaData{
  position: relative;
  height: 100%;
}
.noneData{
  background-color: #eeeeee;
  color: #999999;
  font-size: 12px;
  text-align: center;
  padding-top: 15px;
  img{
    width: 26px;
    height: 26px;
  }
}
.havaData{
  img{
    width: 100%;
    height: 100%;
  }
}
</style>

2、壓縮圖片上傳

<template>
  <div class="upload-wrapper">
    <div v-if="!imgUrl" class="noneData">
      <div class="uploadImg" @click="openLocals">
      </div>
      <form :id="fileName+'Form'" enctype="multipart/form-data" style="display:none;">
        <input ref="pathClear" type="file"  accept="image/*" :name="fileName" @change="fileChanged"/>
      </form>
    </div>
    <div v-else class="havaData">
     <div class="havaDataimg">
        <div class="img_wap">
          <img :src="imgUrl" alt="" @click.stop="bigPicture">
        </div>
        <div class="remove" @click.stop="removePackage"></div>
     </div>
    </div>
    <div class="maxImg" @click="minImg" v-if="maxImg">
      <img :src="imgUrl" alt="">
    </div>
  </div>
</template>
<script>
import $ from 'jquery';
import { Indicator, Toast } from 'mint-ui';
import axios from 'axios';
export default {
  data() {
    return {
      maxImg: false,
      xhr: null,
      ot: null,
      oloaded: null,
    };
  },
  props: {
    // file控件名稱
    fileName: {
      type: String,
      required: true
    },
    // 圖片地址
    imgUrl: {
      type: String,
      default: '',
      required: true
    },
    // 圖片地址
    isMaxIMg: {
      type: String,
      default: '',
      required: true
    },
  },
  methods: {
    // 查看大圖
    bigPicture() {
      console.log(this.isMaxIMg);
      if (this.isMaxIMg === '0') {
        return false;
      }
      this.maxImg = true;
    },
    // 恢復小圖
    minImg() {
      this.maxImg = false;
    },
    // 刪除圖片
    removePackage() {
      let _self = this;
      _self.$emit('removeImg');
    },
    // 上傳圖片
    openLocals() {
      $(`input[type='file'][name='${this.fileName}']`).click();
    },
    fileChanged() {
      this.UpladFile();
    },
    // 三個參數
    // file:一個是文件(類型是圖片格式),
    // w:一個是文件壓縮的后寬度,寬度越小,字節越小
    // objDiv:一個是容器或者回調函數
    // photoCompress()
    photoCompress(file, w, objDiv) {
      let that = this;
      let ready = new FileReader();
      // 開始讀取指定的Blob對象或File對象中的內容. 當讀取操作完成時,readyState屬性的值會成為DONE,如果設置了onloadend事件處理程序,則調用之.同時,result屬性中將包含一個data: URL格式的字符串以表示所讀取文件的內容.
      ready.readAsDataURL(file);
      ready.onload = function() {
        let re = this.result;
        that.canvasDataURL(re, w, objDiv);
      };
    },
    canvasDataURL(path, obj, callback) {
      let img = new Image();
      img.src = path;
      img.onload = function() {
        let that = this;
        // 默認按比例壓縮
        let w = that.width;
        let h = that.height;
        let scale = w / h;
        w = obj.width || w;
        h = obj.height || (w / scale);
        let quality = 0.7;  // 默認圖片質量為0.7
        // 生成canvas
        let canvas = document.createElement('canvas');
        let ctx = canvas.getContext('2d');
        // 創建屬性節點
        let anw = document.createAttribute('width');
        anw.nodeValue = w;
        let anh = document.createAttribute('height');
        anh.nodeValue = h;
        canvas.setAttributeNode(anw);
        canvas.setAttributeNode(anh);
        ctx.drawImage(that, 0, 0, w, h);
        // 圖像質量
        if (obj.quality && obj.quality <= 1 && obj.quality > 0) {
          quality = obj.quality;
        }
        // quality值越小,所繪制出的圖像越模糊
        let base64 = canvas.toDataURL('image/jpeg', quality);
        // 回調函數返回base64的值
        callback(base64);
      };
    },
    /**
     * 將以base64的圖片url數據轉換為Blob
     * @param urlData
     *            用url方式表示的base64圖片數據
     */
    convertBase64UrlToBlob(urlData) {
      let arr = urlData.split(',');
      let mime = arr[0].match(/:(.*?);/)[1];
      let bstr = atob(arr[1]);
      let n = bstr.length;
      let u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new Blob([u8arr], { type: mime });
    },
    // 上傳文件方法
    UpladFile() {
      let that = this;
      let fileElement = $(`input[type='file'][name='${that.fileName}']`);
      let filename = fileElement.val();
      let ext = filename.substring(filename.lastIndexOf('.')).toLowerCase();
      if (ext !== '.jpg' && ext !== '.png' && ext !== '.jpeg' && ext !== '.bmp') {
        Toast({
          message: '僅支持.jpg、.png、.jpeg、.bmp的圖片格式',
          position: 'bottom',
          duration: 2000
        });
        return false;
      }
      let fileObj = fileElement[0].files[0];
      let form = new FormData(); // FormData 對象
      if (fileObj.size / 1024 > 1025) { // 大於1M,進行壓縮上傳
        that.photoCompress(fileObj, {
          quality: 0.2
        }, function(base64Codes) {
          let bl = that.convertBase64UrlToBlob(base64Codes);
          form.append('file', bl, 'file_' + Date.parse(new Date()) + '.jpg'); // 文件對象
          let config = {
            headers: { 'Content-Type': 'multipart/form-data' }
          };
          Indicator.open('圖片正在上傳中...');
          axios.post(`${process.env.UPLOAD_HOST}`, form, config).then((res) => {
            console.log(res);
            let data = res.data;
            Indicator.close();
            if (data) {
              that.$emit('uploadSuccess', data[0]);
            }
          }).catch(() => {
            Indicator.close();
            Toast({
              message: '圖片過大上傳失敗',
              position: 'bottom',
              duration: 2000
            });
          });
        });
      } else { // 小於等於1M 原圖上傳
        Indicator.open('圖片正在上傳中...');
        form.append('file', fileObj); // 文件對象
        axios.post(`${process.env.UPLOAD_HOST}`, form).then((res) => {
          console.log(res);
          let data = res.data;
          Indicator.close();
          if (data) {
            that.$emit('uploadSuccess', data[0]);
          }
        }).catch(() => {
          Indicator.close();
          Toast({
            message: '圖片過大上傳失敗',
            position: 'bottom',
            duration: 2000
          });
        });
      }
    },
  }
};
</script>

<style lang="less" scoped>
.upload-wrapper{
  position: relative;
  height: 172px;
}
.noneData,.havaData{
  height: 100%;
  padding: 15px 16vw;
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  .uploadImg{
    width: 102px;
    height: 102px;
    background-size: 100% 100%;
    background-image: url(./imgs/xh_pfgy_upload.png);
  }
  .havaDataimg{
    position: relative;
    width: 100%;
    height: 100%;
    border: 1px solid #eeeeec;
    overflow: hidden;
    .img_wap{
      width: 100%;
      height: 0px;
      padding-bottom: 56%;
      position: relative;
      img{
        width: 100%;
        position: absolute;
        top: -30%;
        left: 0px;
      }
    }
    .remove{
      position: absolute;
      top: 0;
      right: 0;
      width: 18px;
      height: 18px;
      background: url('./imgs/icon_close.png') rgba(255, 255, 255, 0.8) center center no-repeat;
      background-size: cover;
      border-radius: 50%;
    }
  }
}
// 大圖效果
.maxImg{
  position: fixed;
  top: 0px;
  left: 0px;
  right: 0px;
  bottom: 0px;
  overflow: auto;
  background-color:rgba(0, 0, 0, 0.5);
  z-index: 100;
  padding: 20px;
  display: flex;
  justify-content: center;
  align-items: center;
  img{
    max-width: 100%;
    max-height: 100%;
  }
}
</style>

3、轉為base64上傳

<template>
  <div>
    <div style="padding:20px;">
      <!-- <div class="show">
        <div class="picture" :style="'backgroundImage:url('+headerImage+')'"></div>
      </div> -->
      <div class="havaDataimg">
         <div class="img_wap">
          <img  :src="headerImage"  alt="">
        </div>
        <div class="remove"></div>
      </div>
      <div style="margin-top:20px;">
        <input type="file" id="upload" accept="image/*" @change="upload">
        <label for="upload"></label>
      </div>
    </div>
  </div>
</template>
<script>
import Exif from 'exif-js';
import { Toast } from 'mint-ui';
export default {
  data() {
    return {
      headerImage: '',
      picValue: ''
    };
  },
  methods: {
    upload(e) {
      let files = e.target.files || e.dataTransfer.files;
      if (!files.length) return;
      this.picValue = files[0];
      let filename = this.picValue.name;
      let ext = filename.substring(filename.lastIndexOf('.')).toLowerCase();
      if (ext !== '.jpg' && ext !== '.png' && ext !== '.jpeg' && ext !== '.bmp') {
        Toast({
          message: '僅支持.jpg、.png、.jpeg、.bmp的圖片格式',
          position: 'bottom',
          duration: 2000
        });
        return false;
      }
      this.imgPreview(this.picValue);
    },
    imgPreview(file) {
      let self = this;
      let Orientation;
      // 去獲取拍照時的信息,解決拍出來的照片旋轉問題
      Exif.getData(file, function() {
        Orientation = Exif.getTag(this, 'Orientation');
      });
      // 看支持不支持FileReader
      if (!file || !window.FileReader) return;

      if (/^image/.test(file.type)) {
        // 創建一個reader
        let reader = new FileReader();
        // 將圖片2將轉成 base64 格式
        reader.readAsDataURL(file);
        // 讀取成功后的回調
        reader.onloadend = function () {
          let result = this.result;
          let img = new Image();
          img.src = result;
          // 判斷圖片是否大於100K,是就直接上傳,反之壓縮圖片
          if (this.result.length <= (100 * 1024)) {
            self.headerImage = this.result;
            self.postImg();
          } else {
            img.onload = function () {
              let data = self.compress(img, Orientation);
              self.headerImage = data;
              self.postImg();
            };
          }
        };
      }
    },
    postImg() {
      // 這里寫接口
    },
    rotateImg(img, direction, canvas) {
      // 最小與最大旋轉方向,圖片旋轉4次后回到原方向
      const min_step = 0;
      const max_step = 3;
      if (img == null) return;
      // img的高度和寬度不能在img元素隱藏后獲取,否則會出錯
      let height = img.height;
      let width = img.width;
      let step = 2;
      if (step == null) {
        step = min_step;
      }
      if (direction === 'right') {
        step++;
        // 旋轉到原位置,即超過最大值
        step > max_step && (step = min_step);
      } else {
        step--;
        step < min_step && (step = max_step);
      }
      // 旋轉角度以弧度值為參數
      let degree = step * 90 * Math.PI / 180;
      let ctx = canvas.getContext('2d');
      switch (step) {
        case 0:
          canvas.width = width;
          canvas.height = height;
          ctx.drawImage(img, 0, 0);
          break;
        case 1:
          canvas.width = height;
          canvas.height = width;
          ctx.rotate(degree);
          ctx.drawImage(img, 0, -height);
          break;
        case 2:
          canvas.width = width;
          canvas.height = height;
          ctx.rotate(degree);
          ctx.drawImage(img, -width, -height);
          break;
        case 3:
          canvas.width = height;
          canvas.height = width;
          ctx.rotate(degree);
          ctx.drawImage(img, -width, 0);
          break;
      }
    },
    compress(img, Orientation) {
      let canvas = document.createElement('canvas');
      let ctx = canvas.getContext('2d');
      // 瓦片canvas
      let tCanvas = document.createElement('canvas');
      let tctx = tCanvas.getContext('2d');
      let initSize = img.src.length;
      let width = img.width;
      let height = img.height;
      // 如果圖片大於四百萬像素,計算壓縮比並將大小壓至400萬以下
      let ratio;
      if ((ratio = width * height / 4000000) > 1) {
        console.log('大於400萬像素');
        ratio = Math.sqrt(ratio);
        width /= ratio;
        height /= ratio;
      } else {
        ratio = 1;
      }
      canvas.width = width;
      canvas.height = height;
      //        鋪底色
      ctx.fillStyle = '#fff';
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      // 如果圖片像素大於100萬則使用瓦片繪制
      let count;
      if ((count = width * height / 1000000) > 1) {
        console.log('超過100W像素');
        count = ~~(Math.sqrt(count) + 1); // 計算要分成多少塊瓦片
        //            計算每塊瓦片的寬和高
        let nw = ~~(width / count);
        let nh = ~~(height / count);
        tCanvas.width = nw;
        tCanvas.height = nh;
        for (let i = 0; i < count; i++) {
          for (let j = 0; j < count; j++) {
            tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh);
            ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh);
          }
        }
      } else {
        ctx.drawImage(img, 0, 0, width, height);
      }
      // 修復ios上傳圖片的時候 被旋轉的問題
      if (Orientation !== '' && Orientation !== 1) {
        switch (Orientation) {
          case 6:// 需要順時針(向左)90度旋轉
            this.rotateImg(img, 'left', canvas);
            break;
          case 8:// 需要逆時針(向右)90度旋轉
            this.rotateImg(img, 'right', canvas);
            break;
          case 3:// 需要180度旋轉
            this.rotateImg(img, 'right', canvas);// 轉兩次
            this.rotateImg(img, 'right', canvas);
            break;
        }
      }
      // 進行最小壓縮
      let ndata = canvas.toDataURL('image/jpeg', 0.7);
      console.log('壓縮前:' + initSize);
      console.log('壓縮后:' + ndata.length);
      console.log('壓縮率:' + ~~(100 * (initSize - ndata.length) / initSize) + '%');
      tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;
      return ndata;
    },
  }
};
</script>

<style lang="less" scoped>
*{
  margin: 0;
  padding: 0;
}
/* .show {
  width: 100px;
  height: 100px;
  overflow: hidden;
  position: relative;
  border-radius: 50%;
  border: 1px solid #d5d5d5;
}
.picture {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
} */
.havaDataimg{
  position: relative;
  width: 100%;
  height: 100%;
  border: 1px solid #eeeeec;
  overflow: hidden;
  .img_wap{
    width: 100%;
    height: 0px;
    position: relative;
    padding-bottom: 56.25%;
    img{
      width: 100%;
      position: absolute;
      top: -30%;
      left: 0px;
    }
  }
}
</style>

 4引入組件使用

import uploadImg from '@/components/upload/prescriptionUploadImg';


components: {
    'uploadImg': uploadImg,
  },





<uploadImg :imgUrl="pic_url" :fileName="'Image'" @uploadSuccess="addImgUrl" @removeImg="removeImgUrl"></uploadImg>

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM