簡單記錄下今早作H5上傳中一些代碼還有坑css
1、展現html
由於前端上傳文件是必須經過form表單的,不能使用ajax,這樣的話一個移動頁面放入一個type爲file的input真心不怎麼好看,以下圖,很挫有沒有前端
解決辦法找了下,PC上有些是把這個input換成flash,採用jquery的工具庫好比uploadify來作,可是移動端大部分瀏覽器是不支持flash的。因此最後採用的辦法仍是用form表單的形式,只是把這個form和input的透明度設置爲0,讓它們和準備顯示的內容同時在一個div中,顯示的內容能夠作成本身想要的樣子。代碼以下:html5
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"> <title></title> <style> div{width: 100%;} .logo img{display:block; margin:0 auto;} .upload{position: relative;width: 80px;height: 18px;line-height: 18px;background: #2fc7c9;text-align: center; color: #FFF;padding: 0px 5px;-webkit-border-radius: 2px;border-radius: 2px; margin: 0 auto; } .upload form{width:100%;position:absolute; left:0; top:0;opacity:0; filter:alpha(opacity=0);} .upload form input{width: 100%;} </style> </head> <body> <div class="logo"> <img src="img/1.jpg" /> </div> <div class="upload"> <p>上傳圖片</p> <form> <input type="file" /> </form> </div> </body> </html>
樣子如左圖,這樣展示就在「上傳圖片」這個p標籤中,點擊它就有選擇file的效果jquery
2、JS代碼web
我這邊寫的蠻簡單的,只是用了下h5上傳的的基本功能ajax
html代碼以下,action爲要請求的路徑,我這邊作的是當文件發生改變時就上傳修改頭像,input標籤的name屬性不能省去,具體跟後端接口有關canvas
<form id="uploadForm" enctype="multipart/form-data" method="post" action="XXXXXX"> <input type="file" name="imageFile" id="imageFile" onchange="fileSelected()" /> </form>
var iMaxFilesize = 2097152; //2M window.fileSelected = function() { var oFile = document.getElementById('imageFile').files[0]; //讀取文件 var rFilter = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i; if (!rFilter.test(oFile.type)) { alert("文件格式必須爲圖片"); return; } if (oFile.size > iMaxFilesize) { alert("圖片大小不能超過2M"); return; } var vFD = new FormData(document.getElementById('uploadForm')), //創建請求和數據 oXHR = new XMLHttpRequest(); oXHR.addEventListener('load', function(resUpload) { //成功 }, false); oXHR.addEventListener('error', function() { //失敗 }, false); oXHR.addEventListener('abort', function() { //上傳中斷 }, false); oXHR.open('POST', actionUrl); oXHR.send(vFD); };
3、圖片壓縮後端
在開發中,特別是在移動端每每一張圖片大小在3,4M左右,這樣的圖片上傳會給服務器帶來很多壓力,同時也有很多接口對img的大小有所要求,好比不能超過200K,那手機相冊的照片大可能是見了鬼的,都上傳不了。在html5的功能中,能夠將圖片壓縮大小(尺寸)放到canvas畫布上,而後截取canvas畫布上的圖片,轉變爲二進制的數據,經過blob進行再次壓縮生成圖片文件,這樣手機上4M左右圖片傳到服務器上也就100K左右了。數組
<input type="file" name="imageFile" id="imageFile" onchange="fileSelected()" /> <form id="uploadForm" enctype="multipart/form-data" method="post" action="XXXXXX"> <input hidden="hidden" name="param" value="test" /> </form>
當文件改變時,對圖片進行壓縮上傳
window.fileSelected = function() { var _this = $(this); var file = this.files[0]; var rFilter = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i; if(!rFilter.test(file.type)) { alert("文件格式必須爲圖片"); return; } /*開始進行網絡加載*/ _this.css("display", "none"); //目的是爲了屏蔽點擊事件 var reader = new FileReader() , image = new Image() , canvas = document.createElement("canvas") , ctx = canvas.getContext("2d"); reader.onload = function() { //文件加載完成 var url = reader.result; image.src = url; }; image.onload = function() { //圖片加載完成 var w = image.naturalWidth , h = image.naturalHeight , scale = 3; //圖片縮放比例,這裏是把圖片大小高寬均縮小3倍 canvas.width = w / scale; canvas.height = h / scale; ctx.drawImage(image, 0 , 0 , w , h , 0 , 0 , canvas.width , canvas.height); fileUpload(); }; reader.readAsDataURL(file); //用文件加載器加載文件 function fileUpload() { //文件上傳方法 var quality = 0.3; //圖片的質量,這裏設置的是0.3 var data = canvas.toDataURL("image/jpeg", quality);//獲取畫布圖片,而且要jpg格式 data = data.split(',')[1]; data = window.atob(data); var ia = new Uint8Array(data.length); for(var i = 0; i < data.length; i++) { ia[i] = data.charCodeAt(i); } var blob = new Blob([ia], { //以上均爲二進制參數處理,從而獲取一個blob對象 type: "image/jpeg" }); var fd = new FormData(document.getElementById("uploadForm")); fd.append("XXX" , blob , "upload.jpg"); //向form中加入圖片數據,name屬性是XXX,文件名是upload.jpg var xhr = new XMLHttpRequest(); xhr.addEventListener('load', function(resUpload) { _this.css("display", ""); //請求成功 }, false); xhr.addEventListener('error', function(){ _this.css("display", ""); //請求失敗 }, false); xhr.addEventListener('abort', function(){ _this.css("display", ""); //上傳終止 }, false); xhr.open('POST', "http://XXXXXXXXXXXXX");//請求地址 xhr.send(fd);//發送 } };
關鍵代碼
reader.readAsDataURL(file);
將文件讀取爲DataURL
canvas.toDataURL(type, encoderOptions);
實際上就是讀取canvas畫布上圖片的數據。其默認是png格式,若是第一個參數type是image/jpeg的話,第二個參數encoderOptions就能夠用來設置圖片的壓縮質量。
var quality = 0.3; //圖片的質量,這裏設置的是0.3 var data = canvas.toDataURL("image/jpeg", quality);//獲取畫布圖片,而且要jpg格式 data = data.split(',')[1]; data = window.atob(data); var ia = new Uint8Array(data.length); for(var i = 0; i < data.length; i++) { ia[i] = data.charCodeAt(i); } var blob = new Blob([ia], { //以上均爲二進制參數處理,從而獲取一個blob對象 type: "image/jpeg" });
這一段代碼的的目的是爲了解碼圖片數據,而後返回一個Blob對象,對象的格式是jpg。aton其做用是作解碼,由於圖片格式的base64,該方法解碼出來多是一堆亂碼,Uint8Array返回的是8進制整型數組。
Blob是存儲二進制文件的容器,典型的Blob對象是一個圖片或者聲音文件,其默認是PNG格式。最後的blob就能夠傳給服務端了。
整理成一個插件,代碼以下
(function(window,undefind){ function imgUpLoad(options){ var defaults = { inputId : "" , //輸入框ID formId : "" , //表單ID paramName : "" , //輸入框的name requestUrl : "" , //請求的URL imgSizeScale : 3 , //圖片縮放比例 imgQuality : 0.3 , //圖片質量 sucFun : undefind , //成功的回調函數 errFun : undefind , //失敗的回調函數 abortFun : undefind //上傳取消的回調函數 }; var opts = $.extend(true , defaults , options || {}) , _this = document.getElementById(opts.inputId); _this.addEventListener('change' , fileChange , false); function fileChange() { var file = _this.files[0]; var rFilter = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i; if(!rFilter.test(file.type)) { alert("文件格式必須爲圖片"); return; } var reader = new FileReader() , image = new Image() , canvas = document.createElement("canvas") , ctx = canvas.getContext("2d"); startFileLoad(reader , image , canvas , ctx); } function startFileLoad(reader , image , canvas , ctx){ //文件加載 reader.onload = function() { //文件加載完成 var url = reader.result; image.src = url; }; image.onload = function() { //圖片加載完成 var w = image.naturalWidth , h = image.naturalHeight; canvas.width = w / opts.imgSizeScale; canvas.height = h / opts.imgSizeScale; ctx.drawImage(image, 0 , 0 , w , h , 0 , 0 , canvas.width , canvas.height); fileUpload(canvas); }; reader.readAsDataURL(file); } function fileUpload(canvas){ //文件上傳 var blob = getBlob(canvas); var fd = new FormData(document.getElementById(opts.formId)); fd.append(opts.paramName , blob , "upload.jpg"); var xhr = new XMLHttpRequest(); xhr.addEventListener('load', function(resUpload) { //請求成功 _this.style.display = ""; if(opts.sucFun && typeof opts.sucFun === "function") opts.sucFun(resUpload.currentTarget.response); }, false); xhr.addEventListener('error', function(){ //請求失敗 _this.style.display = ""; if(opts.errFun && typeof opts.errFun === "function") opts.errFun(); }, false); xhr.addEventListener('abort', function(){ //上傳終止 _this.style.display = ""; if(opts.abortFun && typeof opts.abortFun === "function") opts.abortFun(); }, false); xhr.open('POST', opts.requestUrl);//請求地址 xhr.send(fd);//發送 } function getBlob(canvas){ //獲取blob對象 var data = canvas.toDataURL("image/jpeg", opts.imgQuality); data = data.split(',')[1]; data = window.atob(data); var ia = new Uint8Array(data.length); for(var i = 0; i < data.length; i++) { ia[i] = data.charCodeAt(i); } return new Blob([ia], { type: "image/jpeg" }); } } window.imgUpLoad = imgUpLoad; })(window);