最近很好奇前端的文件上傳功能,由於公司要求作一個支持圖片預覽的圖片上傳插件,因此本身搜了不少相關的插件,雖然功能不少,但有些地方不能根據公司的想法去修改,並且須要依賴jQuery或Bootstrap庫,因此我就想學下圖片上傳的原理,試着作一個原生無依賴,並且足夠靈活的圖片上傳插件。話很少說,開整。css
用戶引入插件代碼後,只須要像下面這樣,設置一些參數,而後執行一個方法就生成一個圖片上傳組件。html
<div id="upload"></div> // 這是用來生成圖片上傳組件的div
<script> // 設置參數 var options = { path: '/', // 上傳圖片時指定的地址路徑,相似form變淡的action屬性 onSuccess: function (res) { // 上傳成功後執行的方法,res是接收的ajax響應內容 console.log(res); }, onFailure: function (res) { // 上傳失敗後執行的方法,res是接收的ajax響應內容 console.log(res); } } // 執行生成圖片上傳插件的方法, 第一個參數是上面提到的準備生成組件的div選擇器,第二個參數是設置的組件信息,執行方法後返回一個函數指針,指向執行上傳功能的函數,經過把執行上傳功能的函數暴露出來,用戶就能夠本身控制什麼時候上傳圖片了。 var upload = tinyImgUpload('#upload', options); </script>
咱們須要思考用戶如何引入咱們的插件代碼。
插件代碼應該分爲兩個文件,一個CSS文件(tinyImgUpload.css),用於定義組件的基本樣式,此外用戶能夠根據本身的想法本身DIY樣式,另外一個是控制功能邏輯的js文件(tinyImgUpload.js)。用戶引入這兩個文件後,就能夠實現圖片上傳組件了。前端
具體實現的時候,主要涉及到兩個地方,一個是讀取本地文件,實現圖片上傳前能夠預覽的功能,一個是圖片上傳功能。html5
這裏用到了html5的File API,使用這個API能夠在客戶端驗證上傳的文件類型,限制文件大小,固然,在這裏咱們主要用到FileReader接口來讀取文件,Filereader.readAsDataURL()返回的事件對象的result屬性就是將文件編碼爲base64的數據地址,相似下面這樣的,把他賦值給src屬性,圖片就顯示出來了。
具體代碼以下,完整代碼能夠從這裏下載(tinyImgUpload.js )node
// 預覽圖片 //處理input選擇的圖片 function handleFileSelect(evt) { var files = evt.target.files; for(var i=0, f; f=files[i];i++){ // 過濾掉非圖片類型文件 if(!f.type.match('image.*')){ continue; } // 過濾掉重複上傳的圖片 var tip = false; for(var j=0; j<(ele.files).length; j++){ if((ele.files)[j].name == f.name){ tip = true; break; } } if(!tip){ // 圖片文件綁定到容器元素上 ele.files.push(f); var reader = new FileReader(); reader.onload = (function (theFile) { return function (e) { var oDiv = document.createElement('div'); oDiv.className = 'img-thumb img-item'; // 向圖片容器裏添加元素 oDiv.innerHTML = '<img class="thumb-icon" src="'+e.target.result+'" />'+ '<a href="javscript:;" class="img-remove">x</a>' ele.insertBefore(oDiv, addBtn); }; })(f); reader.readAsDataURL(f); } } } // input#img-file-input是一個隱藏的上傳圖片的input控件,當選擇圖片的時候會觸發change事件 document.querySelector('#img-file-input').addEventListener('change', handleFileSelect, false);
上傳文件以前,咱們須要考慮如何保存用戶已經選擇的文件對象,因爲用戶可能屢次選擇,也可能在上傳以前又刪除了幾個圖片,因此須要有一個地方實時保存圖片信息,而且要和預覽的圖片保持同步,預覽顯示有哪幾張圖片,這個地方就存儲幾張圖片。我採用的方式是將文件信息組裝成一個數組,而後綁定到組件元素(#img-container)的自定義屬性上,上面代碼中的「ele.files.push(f)」作的就是這件事。git
ajax是不能直接上傳文件對象的,咱們能夠經過FormData對象,FormData是XMLHttpRequest Level 2添加的一個新接口,使用一系列的鍵值對來模擬一個完整的表單,而後使用XMLHttpRequest異步發送這個"表單"。具體代碼以下。github
// 上傳圖片 function uploadImg() { var xhr = new XMLHttpRequest(); var formData = new FormData(); for(var i=0, f; f=ele.files[i]; i++){ formData.append('files', f); } xhr.onreadystatechange = function (e) { if(xhr.readyState == 4){ if(xhr.status == 200){ options.onSuccess(xhr.responseText); }else { options.onFailure(xhr.responseText); } } } xhr.open('POST', options.path, true); xhr.send(formData); }
咱們寫了一個基本的佈局樣式做爲默認樣式,用戶能夠根據本身的需求進行DIY。這裏是完整的樣式文件(tinyImgUpload.css )。
基本的效果圖以下。
若是咱們想觸發上傳圖片,能夠把tinyImgUpload('#upload', options)返回的upload方法綁定到一個按鈕上,監聽點擊事件。ajax
<button class="submit">submit</button> <script> document.getElementsByClassName('submit')[0].onclick = function (e) { upload(); } </script>
這樣當我點擊圖片的時候,圖片就會上傳,交給服務器端處理了。
上傳按鈕
服務器接收的圖片數組
爲了測試圖片上傳好很差用,我本身搭建了一個圖片接收的服務器,使用的是node.js,經過multer實現,若是你們感興趣能夠點擊這裏。服務器
圖片上傳的關鍵部分就是如何讀取本地文件實現預覽,以及經過FormData對象構造一個表單對象實現ajax異步上傳文件。目前這個插件的功能還不夠完善,我把它放到了Github上(https://github.com/gitwd/tinyImgUpload),後續會慢慢優化,歡迎你們提出寶貴意見。
https://www.html5rocks.com/en/tutorials/file/dndfiles/
http://codecloud.net/9276.html
http://www.zhangxinxu.com/wordpress/2011/09/%E5%9F%BA%E4%BA%8Ehtml5%E7%9A%84%E5%8F%AF%E9%A2%84%E8%A7%88%E5%A4%9A%E5%9B%BE%E7%89%87ajax%E4%B8%8A%E4%BC%A0/
https://cnodejs.org/topic/50ce2bbb637ffa415589a50f