vue圖片上傳組件

前言:不少項目中都須要用到圖片上傳功能,而其多處使用的要求,爲了不重複造輪子,讓我決定花費一些時間去深刻了解,最終封裝了一個vue的圖片上傳組件。現將總結再次,但願有幫助。html

Layout

  <div class="upload-wraper">
   <input type="file" id="upload_ele" multiple="false" accept="image/*" @change="uploadFile()" />
</div>

type=file將類型設置爲選擇文件vue

multiple是否容許文件的多選node

accept="image/*" 將文件的類型限制爲image類型,*包括全部格式的圖片web

change事件當type設置爲file後,出發的事件爲change,也可經過submit實現canvas

這裏佈局的話,由於是vue組件因此簡單點,不須要多個input構成form表單,而後經過submit提交,一個input經過change事件來實現上傳後端

Js

Basic information for uploading files

  let oFIle = document.getElementById('upload-ele').files[0];

files是input設置爲file後的一個js內置對象。files對象死一個read-only屬性,不可被修改!api

打印出oFile後能夠看到該文件對象的basic information.以下:服務器

isClosed:false 是否已經結束,能夠理解爲標籤是否閉合網絡

lastModified:1539602132000最後更改的時間timeStampapp

lastModifiedDate:Mon Oct 15 2018 19:15:32 GMT+0800 (CST) {}最後更改時間

name:"D9791645A5DF19D17FD7392A080E7A28.jpg"圖片的名稱

path:"/Users/mac/Documents/D9791645A5DF19D17FD7392A080E7A28.jpg"圖片所在的路徑爲本地路徑

Size:38938圖片的大小信息 單位爲kb

type:'image/jpeg'圖片的類型

webkitRelativePath:""文件相關的路徑

File Size Processing

大小判斷

  (oFile.size / 1024) > 1024

1M = 1024KB

Smaller

 let form = new FormData();
  form.append('file',oFile);
  let xhr = new XMLHttpRequest();
  xhr.open('post',url,true);
  xhr.timeout = 30 * 1000;
  xhr.upload.onprogress = this.progress;
  xhr.onload = this.uploadComplete;
  xhr.onerror = this.uploadFailed;
  xhr.upload.onloadstart = () => {
      let date = new Date().getTime();
      let initSize = 0;
  }
  xhr.send(form);

XMLHttpRequest()是js內置對象,可使用該屬性實現請求頭的處理操做。

xhr.open(); 請求方法: post,url: 服務器接受的地址,true/false 是否異步

xhr.timeout; 設置超時時間,據狀況而定

xhr.ontimeout; 超時處理,通常爲取消請求

xhr.upload.onprogress; 進程處理 ,上傳文件的進度處理

xhr.onload; 請求成功處理

xhr.onerror; 請求失敗處理

Xhr.upload.onloadstart; 請求開始處理的操做,通常建立時間戳,初始化大小。

xhr.send(); 請求配置完畢,發送請求

這裏小於1M的文件是能夠直接經過放到formData中,經過配置xhr將圖片對象上傳到oss,在請求成功時拿到圖片的網絡路徑供後,提供給後端。

Larger

why:爲何要對大於1M的圖片進行處理呢?由於文件在大於1M的通常是上傳失敗的。常見的ftp文件上傳時,默認是2M,大於時,會上傳失敗,因此這裏的圖片上傳進行了大於1M壓縮的處理。

how:流程與小於1M時十分類似,不過,這裏添加了圖片的壓縮處理。

more:通常在較大文件處理時,後端也是能夠進行處理的,單獨提供較大圖片的接口。這時,咱們就不須要進行壓縮了,只須要在判斷大於1024KB時接口更換爲處理較大文件的接口便可。

如何壓縮?

  1. 經過FileReader對象將文件對象讀取成base64格式。

  2. 經過Image對象結合canvas畫布將base格式的圖片將必定的比例縮小後從新保存成爲base64格式。

  3. 將base64格式轉換成Blob流後,圖片就能夠說是壓縮完成了。

  4. 剩下的步驟重複formData,XMLHttpRequest便可完成較大圖片的上傳。這裏須要注意的是,在formData中防止文件時,由於此時是Blob流,因此防止文件時,須要自定義文件格式,這裏的處理是 Blob文件 + 時間戳與.jpg組成。

組件源碼

<template>
  <!-- 圖片上傳組件 -->
    <div class="upload-wraper">
      <input type="file" id="upload-ele" multiple="false"  accept="image/*" @change="uploadFile(url,quality,hasApi,BigUrl)">
      <toast v-model="total.isShow" type="text">{{total.text}}</toast>
    </div>
  </template>
  <script>
  import { Indicator } from 'mint-ui';
  import { Toast } from 'vux';
  export default {
    name: 'uploadImage',
    components: {
      Indicator,
      Toast,
    },
    props: {
      'url': String, //小與1M的api
      'quality': Number, //圖片質量
      'BigUrl': {
        type: String,
        default: '',
      }, //大於1M圖片的api
      'hasApi': {
        type: Boolean,
        default: false
      } //是否對大於1M的圖片單獨分配接口
    },
    data() {
      return {
        total: {isShow:false,text:""}
      }
    },
    methods: {
      uploadFile(url,quality,hasApi,BigUrl) {
        Indicator.open(`上傳中`);
        // files是input設置爲file後的一個內置對象。files對象是一個只讀屬性,不可被修改。
        var oFile = document.getElementById('upload-ele').files[0];
        console.log('File Object',oFile);
        var form = new FormData();
        // 大小判斷 若是大於1M就新型壓縮處理
        // console.log('File Size Unit:KB',(oFile.size / 1024))
        if((oFile.size / 1024) > 1024) {
          if(hasApi) {  
            form.append('file',oFile);
            let xhr = new XMLHttpRequest(); //XMLHttpRequest Object
            xhr.open('post',BigUrl,true); // Method: post,url: server receive address,true/false isAsync
            xhr.timeout = 30 * 1000;  //Timeout one minute;
            xhr.ontimeout = this.uploadTimeout; // Upload Timeout Function
            xhr.upload.onprogress = this.progress; //Progress Function
            xhr.onload = this.uploadComplete; //Upload Success Function
            xhr.onerror = this.uploadFailed; //Upload Failed Funciton
            xhr.upload.onloadstart = () => {
              let date = new Date().getTime(); // TimeStamp Prevents Caching
              let initSize = 0; // Init File Size Zero
            } // Upload Start
            xhr.send(form);
          } else {
            this.imgCompress(oFile,{quality: quality},
            (base64Codes) => {
              var bl = this.convertBase64UrlToBlob(base64Codes);
              form.append("file", bl, "file_" + Date.parse(new Date()) + ".jpg"); // 文件對象
              console.log(form);
              let xhr = new XMLHttpRequest(); // XMLHttpRequest 對象
              xhr.open("post", url, true); //post方式,url爲服務器請求地址,true 該參數規定請求是否異步處理。
              xhr.upload.onprogress = this.progress; //Progress Function
              xhr.ontimeout = this.uploadTimeout; // Upload Timeout Function
              xhr.onload = this.uploadComplete; //Upload Success Function
              xhr.onerror = this.uploadFailed; //Upload Failed Funciton
              xhr.upload.onloadstart = function() {
                let ot = new Date().getTime(); // TimeStamp Prevents Caching
                let oloaded = 0; // Init File Size Zero
              };// Upload Start
              xhr.send(form); 
            })
          }
        } else {
          // 小與1M
          form.append('file',oFile);
          let xhr = new XMLHttpRequest(); //XMLHttpRequest Object
          xhr.open('post',url,true); // Method: post,url: server receive address,true/false isAsync
          xhr.timeout = 30 * 1000;  //Timeout one minute;
          xhr.ontimeout = this.uploadTimeout; // Upload Timeout Function
          xhr.upload.onprogress = this.progress; //Progress Function
          xhr.onload = this.uploadComplete; //Upload Success Function
          xhr.onerror = this.uploadFailed; //Upload Failed Funciton
          xhr.upload.onloadstart = () => {
            let date = new Date().getTime(); // TimeStamp Prevents Caching
            let initSize = 0; // Init File Size Zero
          } // Upload Start
          xhr.send(form); 
        }
      },
      /**
       * @description Request Success
       */
      uploadComplete(evt) {
        let res = JSON.parse(evt.target.responseText);
        if(evt.target.readyState == 4 && evt.target.status == 200) {
          this.$emit('upload',res.result.url);
        } else {
          this.uploadFailed();
        }
      },
      /**
       * @description Request Failed
       */
      uploadFailed(evt) {
        Indicator.close();
        this.total = {
          isShow:true,
          text:"上傳失敗"
        }
      },  
    /**  
     * @description Timeout Function  
     */  
    uploadTimeout(evt) {  
      this.cancleUploadFile(evt)  
      Indicator.close();  
      this.total = {  
        isShow:true,  
        text:"請求超時"  
      }  
    },  
    /**e  
     * @description Upload Cancel  
     */  
    cancleUploadFile(evt) {  
      evt.abort();  
    },  
    /**  
     * @description Requst Loading....  
     */  
    progress(progressEvent) {  
      if(!progressEvent.lengthComputable) {  
        this.total = {  
          isShow:true,  
          text:"進度讀取失敗"  
        }  
        return false;  
      }  
      let precent = Math.floor(100 * progressEvent.loaded / progressEvent.total); //Upload Progress  
      if(precent < 100) {  
        Indicator.open(`上傳中${precent}%`);  
      } else {  
        Indicator.close();  
        this.total = {    
          isShow:true,  
          text:"上傳成功"  
        }  
      }  
    },  
    /**  
      * @description 圖片壓縮  
      * @param {Object} file 壓縮的文件  
      * @param {Number} width 壓縮後端寬度,寬度越小,字節越小  
      */  
    imgCompress(file,width,callBack) {  
      var ready = new FileReader();  
      ready.readAsDataURL(file);  
      ready.onload = () => {  
        this.canvasDataURL(ready.result,width,callBack);  
      }      
    },  
    /**  
     * 將以base64的圖片url數據轉換爲Blob  
     * @param urlData  
     * 用url方式表示的base64圖片數據  
     */  
    convertBase64UrlToBlob(urlData) {  
      var arr = urlData.split(","),  
        mime = arr[0].match(/:(.*?);/)[1],  
        bstr = atob(arr[1]),  
        n = bstr.length,  
        u8arr = new Uint8Array(n);  
      while (n--) {  
        u8arr[n] = bstr.charCodeAt(n);  
      }  
      return new Blob([u8arr], { type: mime });  
    },    
    /**  
     * @description 大於1M的圖片進行從新繪製壓縮  
     */  
    canvasDataURL(path, obj, callback) {  
      var img = new Image();  
      img.src = path;  
      img.onload = () => {  
        // var that = this;  
        // 默認按比例壓縮  
        var w = this.width,  
          h = this.height,  
          scale = w / h;  
        w = obj.width || w;  
        h = obj.height || w / scale;  
        var quality = 0.7; // 默認圖片質量爲0.7  
        //生成canvas  
        var canvas = document.createElement("canvas");  
        var ctx = canvas.getContext("2d");  
        // 建立屬性節點  
        var anw = document.createAttribute("width");  
        anw.nodeValue = w;  
        var anh = document.createAttribute("height");  
        anh.nodeValue = h;  
        canvas.setAttributeNode(anw);  
        canvas.setAttributeNode(anh);  
        ctx.drawImage(img, 0, 0, w, h);  
        // 圖像質量  
        if (obj.quality && obj.quality <= 1 && obj.quality > 0) {  
          quality = obj.quality;  
        }  
        // quality值越小,所繪製出的圖像越模糊  
        var base64 = canvas.toDataURL("image/jpeg", quality);  
        // 回調函數返回base64的值  
        callback(base64);  
      };  
    },  
  }  
}  
</script>  
<style lang="less" scoped>  
  .upload-wraper {  
    width: 100%;  
    height: 100%;  
  }  
</style>

 

這裏是公衆號項目,因此,這裏引入的第三方插件爲mint-ui和vux。具體狀況視狀況而定。

該組件例外封裝了,後端是夠對較大圖片的處理,若是後端已經進行處理,則直接調用。若是沒有處理,則進行壓縮處理,

組件的封裝,可靈活修改,還有不少地方仍待修改

插槽,圖片上傳後,回顯可在組件內部實現。藉由slot更加完美。

該組件限制了圖片文件的上傳,其餘文件則不行。

引入以下:

 <upload-image class="upload" :quality='.7' :url="$base.uploadUrl" :hasApi="false" @upload='uploadImage'></upload-image>

參考文獻

  1. js內置file(文件)對象。https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file

  2. FormData對象的。https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData

  3. XMLHttpRequest對象。https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest

  4. Image對象。https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image

  5. Canvas畫布。內容較多,建議經過學習視頻瞭解。在本文中主要用於大型圖片的壓縮處理

  6. base64和Blob的轉換,百度不少已經封裝好的。可直接使用。eg:http://www.javashuo.com/article/p-qcjidgxo-ks.html


Data: 2018-12-13

author: Csun

相關文章
相關標籤/搜索