工做中遇到的問題記錄:vue開發頭像上傳組件,後端提供接口,需求爲可相冊上傳,可相機拍攝上傳,文件大小限制爲2Mjavascript
這就比較簡單了,H5的標籤足已經能知足咱們的要求了,咱們要作的只是讓它更美觀一點vue
<div class="yb-headSet-but"> <div class="btn-box"> <input type="file" accept="image/*" @change="uploadImg" class="fromAlbum"> //設置input opacity爲0,定位覆蓋a標籤,a標籤設置爲設計稿的按鈕樣式 <a href="" class="weui-but">從相冊選一張</a> </div> <div class="btn-box"> <a href="" class="weui-but">拍一張照片</a> <input type="file" accept="image/*" @change="uploadImg" capture="camera" class="fromCamera"> //二者區別:capture="camera" 可直接調用攝像頭 </div> </div>
利用的是canvas的drawImage 和 toDataURL的api,具體代碼是複製的 https://www.jianshu.com/p/4587312d2f44
修改了幾個大佬筆誤的地方java
imgResize(file, callback) { var _this = this; var fileReader = new FileReader(); fileReader.onload = function() { var IMG = new Image(); IMG.src = this.result; IMG.onload = function() { var w = this.naturalWidth, h = this.naturalHeight, resizeW = 0, resizeH = 0; // maxSize 是壓縮的設置,設置圖片的最大寬度和最大高度,等比縮放,level是報錯的質量,數值越小質量越低 var maxSize = { width: 500, height: 500, level: 0.6 }; if (w > maxSize.width || h > maxSize.height) { var multiple = Math.max(w / maxSize.width, h / maxSize.height); resizeW = w / multiple; resizeH = h / multiple; } else { // 若是圖片尺寸小於最大限制,則不壓縮直接上傳 return callback(file); } var canvas = document.createElement("canvas"); var ctx = canvas.getContext("2d"); if (window.navigator.userAgent.indexOf("iPhone") > 0) { canvas.width = resizeH; canvas.height = resizeW; ctx.rotate(90 * Math.PI / 180); ctx.drawImage(IMG, 0, -resizeH, resizeW, resizeH); } else { canvas.width = resizeW; canvas.height = resizeH; ctx.drawImage(IMG, 0, 0, resizeW, resizeH); } var base64 = canvas.toDataURL("image/" + _this.fileType, maxSize.level); _this.convertBlob(window.atob(base64.split(",")[1]), callback); }; }; fileReader.readAsDataURL(file); },
使用canvas.toDataURL得到的是base64格式,上傳時須要轉換成Blob二進制格式,使用formData提交canvas
//Blob對象生成 convertBlob(base64, callback) { var buffer = new ArrayBuffer(base64.length); var ubuffer = new Uint8Array(buffer); for (var i = 0; i < base64.length; i++) { ubuffer[i] = base64.charCodeAt(i); } var blob; try { blob = new Blob([buffer], { type: "image/" + this.fileType }); } catch (e) { window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; if (e.name === "TypeError" && window.BlobBuilder) { var blobBuilder = new BlobBuilder(); blobBuilder.append(buffer); blob = blobBuilder.getBlob("image/" + this.fileType); } } callback(blob); }, //提交函數 postImg(file) { let image = new FormData(); image.append("file", file, this.random_string(12) + '.' + this.fileType); console.log(image); setHead(image).then(res => { this.$indicator.close(); if (res.Success) { let newPath = res.photoPath +'?t=' + this.random_string(12); this.$store.commit("UPDATE_BASEINFO", { photoPath: newPath }); this.picValue = newPath; this.$messagebox.alert(res.Message); } else { this.$messagebox.alert(res.Message); } }); },
這個坑是這樣的,我使用壓縮過的Blob格式提交後臺時,返回提示文件格式不正確,不屬於jpeg、jpg等,這我就納悶了,我上傳的formData裏面寫明瞭文件格式了啊;
後來通過簡書大佬 一斤代碼 老大的幫助,老大測試後說出了問題所在:那就是 FormData.append('file', file),若是隻有兩個參數,(第三個參數是文件名)的狀況下,默認fileName=「blob」,這樣上次至後臺,若是後臺未作其餘處理的話,就會出現報錯的狀況,後來就添加了隨機文件名,完整代碼以下後端
<template> <div class="yb-page"> <div class="yb-page-inner"> <div class="yb-headSetting"> <div class="yb-headSet-img"> <img :src="picValue" alt="" onerror="this.src='https://ixxxxxx.com/we/tmpls/t9000/img/account/blackHead@2x.png'"> </div> <div class="yb-headSet-but"> <div class="btn-box"> <input type="file" ref="avatarInput" accept="image/*" @change="uploadImg" class="fromAlbum"> <a href="" class="weui-but">從相冊選一張</a> </div> <div class="btn-box"> <a href="" class="weui-but">拍一張照片</a> <input type="file" accept="image/*" @change="uploadImg" capture="camera" class="fromCamera"> </div> </div> </div> </div> </div> </template> <script> import { setHead } from "@/api/user"; export default { data() { return { picValue: this.$store.getters.baseInfo.photoPath, file: null, fileType: '' }; }, methods: { uploadImg(e) { if (e.target.value == "") { return; } this.$indicator.open(); let files = e.target.files || e.dataTransfer.files; if (!files.length) return; this.file = files[0]; this.fileType = this.file.type.split('/')[1]; this.imgResize(files[0], this.postImg); }, postImg(file) { let image = new FormData(); image.append("file", file, this.random_string(12) + '.' + this.fileType); console.log(image); setHead(image).then(res => { this.$indicator.close(); if (res.Success) { let newPath = res.photoPath +'?t=' + this.random_string(12); this.$store.commit("UPDATE_BASEINFO", { photoPath: newPath }); this.picValue = newPath; this.$messagebox.alert(res.Message); } else { this.$messagebox.alert(res.Message); } }); }, imgResize(file, callback) { var _this = this; var fileReader = new FileReader(); fileReader.onload = function() { var IMG = new Image(); IMG.src = this.result; IMG.onload = function() { var w = this.naturalWidth, h = this.naturalHeight, resizeW = 0, resizeH = 0; // maxSize 是壓縮的設置,設置圖片的最大寬度和最大高度,等比縮放,level是報錯的質量,數值越小質量越低 var maxSize = { width: 500, height: 500, level: 0.6 }; if (w > maxSize.width || h > maxSize.height) { var multiple = Math.max(w / maxSize.width, h / maxSize.height); resizeW = w / multiple; resizeH = h / multiple; } else { // 若是圖片尺寸小於最大限制,則不壓縮直接上傳 return callback(file); } var canvas = document.createElement("canvas"); var ctx = canvas.getContext("2d"); if (window.navigator.userAgent.indexOf("iPhone") > 0) { canvas.width = resizeH; canvas.height = resizeW; ctx.rotate(90 * Math.PI / 180); ctx.drawImage(IMG, 0, -resizeH, resizeW, resizeH); } else { canvas.width = resizeW; canvas.height = resizeH; ctx.drawImage(IMG, 0, 0, resizeW, resizeH); } var base64 = canvas.toDataURL("image/" + _this.fileType, maxSize.level); _this.convertBlob(window.atob(base64.split(",")[1]), callback); }; }; fileReader.readAsDataURL(file); }, convertBlob(base64, callback) { var buffer = new ArrayBuffer(base64.length); var ubuffer = new Uint8Array(buffer); for (var i = 0; i < base64.length; i++) { ubuffer[i] = base64.charCodeAt(i); } var blob; try { blob = new Blob([buffer], { type: "image/" + this.fileType }); } catch (e) { window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; if (e.name === "TypeError" && window.BlobBuilder) { var blobBuilder = new BlobBuilder(); blobBuilder.append(buffer); blob = blobBuilder.getBlob("image/" + this.fileType); } } callback(blob); }, random_string(len) { len = len || 32; var chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678"; var maxPos = chars.length; var pwd = ""; for (var i = 0; i < len; i++) { pwd += chars.charAt(Math.floor(Math.random() * maxPos)); } return pwd; } } }; </script>