基于html5的多圖片上傳

基于html5的多圖片上傳

本文是建立在張鑫旭大神的多文圖片傳的基礎之上.
首先先放出來大神多圖片上傳的博客地址: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/

代碼思路

因為html5開放了multiple, 可以讓用戶一次上傳多個文件.
所以,最開始,我們需要建立這樣的html.

<input type="file" name="fuck" multiple="" id="js-file">//上傳文件區域
<div id="js-pre"></div>//圖片預覽區域
<button id="js-button" type="button">提交</button>//提交按鈕

這個時候,我們就可以直接通過獲得input里面的files(不明白的同學可以百度一下),然后循環.提交給服務器.但是,我們會遇到另外一個問題.如果,用戶提交了一個圖片,但是用戶忽然覺得,我不想提交這個.我這個不要了,我要提交其他幾個. 這種情況就非常的尷尬了.(用戶真特么事逼┑( ̄Д  ̄)┍).
所以,我們需要一個數組,臨時存儲這些上傳的數據.當用戶刪除之前上傳的圖片的時候,我們可以在那個臨時的數組中,刪除相應的數據.
打一個比方.用戶通過input選擇了ABC三個圖片.
然后,我們循環input的files,然后依次把ABC加入到我們的臨時數組x中.
這個時候,用戶不想上傳A圖片了,他想刪除A. 于是,貼心的我們,從臨時數組刪除A.
接下來,我們的圖片預覽以及上傳圖片都來自臨時數組x的內容.這樣,無論用戶怎么折騰,貼心無比的我們,都可以滿足用戶的需求.
帶著這樣的思路.我們開始扯淡.


如果有懶惰黨,可以直接下載代碼使用.但是代碼的地址在最下面哦~


完成這個多文件上傳.我們要做到以下幾點要求(所以是幾點?)

  • 可以復用(這段代碼可以在一個頁面多次使用,不會相互沖突)
  • 我們要根據用戶選擇上傳圖片->完成文件的預覽和刪除
  • 用戶選擇提交代碼的時候,進行文件傳輸,傳輸成功的時候,提供success(response){},提供完成相應的回調,同時也提供Failure(response){},進行提交失敗的處理.以及Complete(){},提交完成的處理.

所以,我們從以上幾點,一點一點的開始.


可以復用.
可以復用的意思是,使用者(不想造輪子的程序猿),可以在使用的時候,傳遞一個obj,里面帶有以下參數

  • 用來上傳文件的input的id
  • 觸發提交的button的id
  • 預覽圖片的div的id
  • 后端的url
  • 唯一的文件名稱,為了在html中與其他的多圖片上傳進行劃分
  • 上傳成功的函數
  • 上傳失敗的函數
  • 上傳完成的函數
  • 對上傳圖片過濾的函數(可選) 可供使用者設置處理圖片
    所以,我們可以設置一個obj.
    obj = {
        name: obj.name? obj.name:null,                              //唯一名,用來與其他文件區分
        fileInput: obj.fileInput?obj.fileInput: null,               //html file控件
        upButton: obj.upButton? obj.upButton:null,                  //提交按鈕
        pre: obj.pre?obj.pre:null,                                  //預覽地址
        url: obj.url? obj.url:null,                                 //ajax地址                    
        fileFilter: [],                                             //過濾后的文件數組
        filter: obj.filter?obj.filter:function(files){
            var arrFiles = [];
            for (var i = 0, file; file = files[i]; i++) {
                if (file.type.indexOf("image") == 0) {
                    arrFiles.push(file);     
                } else {
                    alert('文件"' + file.name + '"不是圖片。');    
                }
            }
            return arrFiles;
        },                                                          //過濾的文件,默認判斷如果是圖片可以加入臨時數組
        onSuccess: obj.onSuccess?obj.onSuccess:function(data){
            console.log('success');
        },                                                          //文件上傳成功時
        onFailure: obj.onFailure?obj.onFailure:function(data){
            console.log('error');
        },                                                          //文件上傳失敗時,
        onComplete: obj.onComplete?obj.onComplete:function(){
            console.log('complete');
        },                                                          //文件全部上傳完畢時
    }

然后我們需要一個函數,這個函數里面包含了我們生成多圖片預覽,刪除,上傳等功能.將obj傳入到函數FFile().
這樣,我們就可以通過 var fuck = new FFile(obj) 創建一個可以復用的多文件上傳.
外部構造基本結束,接下來,就可以進行 FFile(){}的內部處理.

    function FFile(obj) {
    this.FileSet = {
        name: obj.name? obj.name:null,                              //唯一名,用來與其他文件區分
        fileInput: obj.fileInput?obj.fileInput: null,               //html file控件
        upButton: obj.upButton? obj.upButton:null,                  //提交按鈕
        pre: obj.pre?obj.pre:null,                                  //預覽地址
        url: obj.url? obj.url:null,                                 //ajax地址                    
        fileFilter: [],                                             //過濾后的文件數組
        filter: obj.filter?obj.filter:function(files){
            var arrFiles = [];
            for (var i = 0, file; file = files[i]; i++) {
                if (file.type.indexOf("image") == 0) {
                    arrFiles.push(file);     
                } else {
                    alert('文件"' + file.name + '"不是圖片。');    
                }
            }
            return arrFiles;
        },                                                          //過濾的文件,默認判斷如果是圖片可以加入臨時數組
        onSuccess: obj.onSuccess?obj.onSuccess:function(data){
            console.log('success');
        },                                                          //文件上傳成功時
        onFailure: obj.onFailure?obj.onFailure:function(data){
            console.log('error');
        },                                                          //文件上傳失敗時,
        onComplete: obj.onComplete?obj.onComplete:function(){
            console.log('complete');
        },      
    }

    this.init();//一會再給你們說這個是干嘛的(笑)
}

接下來我們要處理的事情有兩個.

  1. 我們要根據用戶選擇上傳圖片->完成文件的預覽和刪除
  2. 用戶選擇提交代碼的時候,進行文件傳輸,傳輸成功的時候,提供success(response){},提供完成相應的回調,同時也提供Failure,complate.

首先是第一個

當用戶上傳文件后,會觸發change事件.
然后,我們根據change事件,可以調用一個函數,這個函數把過濾后的圖片(不符合圖片要求),加入到臨時數組fileFilter中.

        funGetFiles: function(e) {          
        // 獲取文件列表對象
        var files = e.target.files || e.dataTransfer.files;
        //繼續添加文件
        this.FileSet.fileFilter = this.FileSet.fileFilter.concat(this.FileSet.filter(files));
        this.funDealFiles();//下面講解這個是啥(┑( ̄Д  ̄)┍)
        return this; //方便進行鏈式操作,類似jq的$().xx().xx().xx();
    },

因為,用戶可能對上傳的圖片,進行刪除.這樣,我們要知道用戶刪除了哪個圖片,我們才能在數組fileFilter中刪除相應的圖片.于是乎,我們就增加了一個索引值.

        //選中文件的處理與回調
    funDealFiles: function() {
        for (var i = 0, file; file = this.FileSet.fileFilter[i]; i++) {
            //增加唯一索引值
            file.index = i;
        }
        //執行選擇回調
        this.onSelect(this.FileSet.fileFilter);
        return this;
    },

然后就要在預覽區域顯示圖片,同時為預覽的圖片增加刪除選項,如何獲得上傳圖片的地址.我采用了FileReader,本文不討論這個.想知道關于FileReader,請自行百度.

    /*
     * 對保存在fileFilter的圖片,生成預覽
     * @param file {array} 傳遞進來的含有所有file的數組
     */
    onSelect: function(files) {
        var html = '', 
            self = this,
            i = 0;
        $(this.FileSet.pre).html();//清空預覽地址
        var funAppendImage = function() { //因為調用FileReader(),在FileReader.onload里面,進行的數值的修改,無法帶到外面來,就像是,一個只允許進不允許出的盒子(原諒我不恰當的比喻),所以,可以通過遞歸的放置,來保存對var html的修改.
            file = files[i];

            if (file) {
                var reader = new FileReader()
                reader.onload = function(e) { //生成的圖片
                    html += '<div id="js-uploadList_'+self.FileSet.name+i+'" class="img-box">';
                    html +=     '<div class="img-border">';
                    html +=         '<span class="js-upload_delete icon-delete_fill red" data-index="'+ i +'"></span>';
                    html +=         '![]('+e.target.result+')</img>';
                    html +=     '</div>';
                    html += '</div>';
                    
                    i++;
                    funAppendImage();
                }
                reader.readAsDataURL(file);
            } else {
                $(self.FileSet.pre).html(html);
                if (html) {
                    //刪除方法
                    $(".js-upload_delete").click(function() {
                        self.funDeleteFile(files[parseInt($(this).attr("data-index"))]);
                        return false;   
                    }); 
                }
            }
        };
        funAppendImage();  
    },

接下來是刪除的方法,這里分為兩個步驟.一個是刪除臨時數組中的圖片,另一個是刪除html中的圖片(在這里,利用了FileSet.name劃分多個多圖片上傳.)

//刪除對應的文件
    funDeleteFile: function(fileDelete) {
        var arrFile = [];
        for (var i = 0, file; file = this.FileSet.fileFilter[i]; i++) {
            if (file != fileDelete) {
                arrFile.push(file);
            } else {
                this.onDelete(fileDelete);  
            }
        }
        this.FileSet.fileFilter = arrFile;
        return this;
    },
    /*
     *刪除函數
     *@param fileDelete {str} 傳遞過來要刪除的File
     */
    onDelete: function(file){//清除圖片
        let self = this;
        $("#js-uploadList_" + self.FileSet.name+ file.index).empty();
    },

然后是第二個

第二個使用了FormData來傳輸多文件的數據.不明白的小伙伴可以繼續百度FormData.代碼簡單,直接閱讀即可.

//文件上傳
    funUploadFile: function() {
        var self = this;    
        if (location.host.indexOf("sitepointstatic") >= 0) {
            //非站點服務器上運行
            return; 
        }
        for (var i = 0, file; file = this.FileSet.fileFilter[i]; i++) {
            (function(file) {   
                var formData = new FormData();
                formData.append(self.FileSet.name,file);
                $.ajax({
                    url: self.FileSet.url,
                    type: 'post',
                    data: formData,
                    contentType: false,  
                    processData: false, 
                    success: function(data) {
                        self.FileSet.onSuccess(data);
                        self.funDeleteFile(file);
                    },
                    error: function(data) {
                        self.FileSet.onFailure(data);
                    }
                })
                if(!self.FileSet.fileFilter.length){
                    //執行完成
                    self.FileSet.onComplete();
                }
            })(file);   
        }   
            
    },

最后就是一開始提到的init()

就是初始化一些東西啦~~~

init: function() {
        var self = this;
        //判斷必須參數是否為空
        if(self.FileSet.fileInput == null || self.FileSet.pre == null || self.FileSet.upButton == null) {
            console.log('必須提供 input的id 預覽區的id 以及 button的id');
            return false;
        }
        //文件選擇控件選擇
        if (self.FileSet.fileInput) {
            // self.FileSet.fileInput.addEventListener("change", function(e) { self.funGetFiles(e); }, false);  
            $(self.FileSet.fileInput).on('change',function(e){
                self.funGetFiles(e);
            })
        }
        
        //上傳按鈕提交
        if (self.FileSet.upButton) {
            // self.FileSet.upButton.addEventListener("click", function(e) { self.funUploadFile(e); }, false);  
            $(self.FileSet.upButton).on('click', function(e) {
                self.funUploadFile(e);
            })
        } 

基本上,一個多圖片上傳的思路就是這樣的~
以上.
另外這里是源代碼地址.https://github.com/fankof29/duotupianshangchuan

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 單例模式 適用場景:可能會在場景中使用到對象,但只有一個實例,加載時并不主動創建,需要時才創建 最常見的單例模式,...
    Obeing閱讀 2,110評論 1 10
  • 《ijs》速成開發手冊3.0 官方用戶交流:iApp開發交流(1) 239547050iApp開發交流(2) 10...
    葉染柒丶閱讀 5,346評論 0 7
  • 工廠模式類似于現實生活中的工廠可以產生大量相似的商品,去做同樣的事情,實現同樣的效果;這時候需要使用工廠模式。簡單...
    舟漁行舟閱讀 7,854評論 2 17
  • 想殺人怎么辦
    玉玲瑯閱讀 234評論 0 1
  • 今天我們去年畫村看年畫,從山邊出發到年畫村,我們坐在車數看能有多少幅年畫,一直到年畫村我共數了320幅年畫,當時我...
    暗香疏影0閱讀 729評論 0 0