上傳圖片,多圖上傳,預覽功能,js原生無依賴

最近很好奇前端的文件上傳功能,由於公司要求作一個支持圖片預覽的圖片上傳插件,因此本身搜了不少相關的插件,雖然功能不少,但有些地方不能根據公司的想法去修改,並且須要依賴jQuery或Bootstrap庫,因此我就想學下圖片上傳的原理,試着作一個原生無依賴,並且足夠靈活的圖片上傳插件。話很少說,開整。css

1. 大致思路

1.1 首先咱們須要考慮用戶如何使用咱們的插件。

用戶引入插件代碼後,只須要像下面這樣,設置一些參數,而後執行一個方法就生成一個圖片上傳組件。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>

1.2 代碼設計

咱們須要思考用戶如何引入咱們的插件代碼。
插件代碼應該分爲兩個文件,一個CSS文件(tinyImgUpload.css),用於定義組件的基本樣式,此外用戶能夠根據本身的想法本身DIY樣式,另外一個是控制功能邏輯的js文件(tinyImgUpload.js)。用戶引入這兩個文件後,就能夠實現圖片上傳組件了。前端

2. 具體實現

具體實現的時候,主要涉及到兩個地方,一個是讀取本地文件,實現圖片上傳前能夠預覽的功能,一個是圖片上傳功能。html5

2.1 讀取本地文件實現預覽

這裏用到了html5的File API,使用這個API能夠在客戶端驗證上傳的文件類型,限制文件大小,固然,在這裏咱們主要用到FileReader接口來讀取文件,Filereader.readAsDataURL()返回的事件對象的result屬性就是將文件編碼爲base64的數據地址,相似下面這樣的,把他賦值給src屬性,圖片就顯示出來了。
base64圖片的樣子
具體代碼以下,完整代碼能夠從這裏下載(tinyImgUpload.jsnode

// 預覽圖片
//處理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);

2.2 上傳圖片

2.2.1 準備文件對象

上傳文件以前,咱們須要考慮如何保存用戶已經選擇的文件對象,因爲用戶可能屢次選擇,也可能在上傳以前又刪除了幾個圖片,因此須要有一個地方實時保存圖片信息,而且要和預覽的圖片保持同步,預覽顯示有哪幾張圖片,這個地方就存儲幾張圖片。我採用的方式是將文件信息組裝成一個數組,而後綁定到組件元素(#img-container)的自定義屬性上,上面代碼中的「ele.files.push(f)」作的就是這件事。git

2.2.2 文件對象咱們準備好後,下一步就是上傳了

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);
}

2.3 設置樣式

咱們寫了一個基本的佈局樣式做爲默認樣式,用戶能夠根據本身的需求進行DIY。這裏是完整的樣式文件(tinyImgUpload.css )。
基本的效果圖以下。
demo樣式
若是咱們想觸發上傳圖片,能夠把tinyImgUpload('#upload', options)返回的upload方法綁定到一個按鈕上,監聽點擊事件。ajax

<button class="submit">submit</button>
<script>
document.getElementsByClassName('submit')[0].onclick = function (e) {
    upload();
}
</script>

這樣當我點擊圖片的時候,圖片就會上傳,交給服務器端處理了。
上傳按鈕
上傳按鈕
服務器接收的圖片
服務器接收的圖片數組

爲了測試圖片上傳好很差用,我本身搭建了一個圖片接收的服務器,使用的是node.js,經過multer實現,若是你們感興趣能夠點擊這裏服務器

3 總結

圖片上傳的關鍵部分就是如何讀取本地文件實現預覽,以及經過FormData對象構造一個表單對象實現ajax異步上傳文件。目前這個插件的功能還不夠完善,我把它放到了Github上(https://github.com/gitwd/tinyImgUpload),後續會慢慢優化,歡迎你們提出寶貴意見。

4 參考目錄

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

相關文章
相關標籤/搜索