html
<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事件來實現上傳後端
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:""文件相關的路徑
(oFile.size / 1024) > 1024
1M = 1024KB
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,在請求成功時拿到圖片的網絡路徑供後,提供給後端。
why:爲何要對大於1M的圖片進行處理呢?由於文件在大於1M的通常是上傳失敗的。常見的ftp文件上傳時,默認是2M,大於時,會上傳失敗,因此這裏的圖片上傳進行了大於1M壓縮的處理。
how:流程與小於1M時十分類似,不過,這裏添加了圖片的壓縮處理。
more:通常在較大文件處理時,後端也是能夠進行處理的,單獨提供較大圖片的接口。這時,咱們就不須要進行壓縮了,只須要在判斷大於1024KB時接口更換爲處理較大文件的接口便可。
如何壓縮?
經過FileReader對象將文件對象讀取成base64格式。
經過Image對象結合canvas畫布將base格式的圖片將必定的比例縮小後從新保存成爲base64格式。
將base64格式轉換成Blob流後,圖片就能夠說是壓縮完成了。
剩下的步驟重複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>
js內置file(文件)對象。https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file
FormData對象的。https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData
XMLHttpRequest對象。https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
Image對象。https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image
Canvas畫布。內容較多,建議經過學習視頻瞭解。在本文中主要用於大型圖片的壓縮處理。
base64和Blob的轉換,百度不少已經封裝好的。可直接使用。eg:http://www.javashuo.com/article/p-qcjidgxo-ks.html
Data: 2018-12-13
author: Csun