web前端之文件上傳

前言

最近太忙一直沒時間認真的寫博客(哈哈哈),最近pm提一個需求,移動端須要一個上傳圖片的功能,容許多選、刪除、預覽、點擊查看大圖並能夠滑動。雖然聽起來不少,可是這個功能在web上實現過啊,使用webuploader妥妥的,而後就拍着胸口答應了下來,並讓B同事作。javascript

開發完成後,後端說同一次上傳多張圖只能發一次請求,納尼。。我沒仔細看過webuploader的API,不知道爲何須要單獨進行上傳,看了一下請求信息,在支持FormData的瀏覽器中使用的FormData來模擬form。那既然這樣也能夠支持多圖一塊兒請求啊(若是webuploader支持或者有其餘考慮,歡迎你們指出),算了,本身造吧,也就有了這篇隨筆。html

1.form表單提交

像我這樣的小白都知道form表單提交以後要刷新頁面,更別說要實現pm提的那些需求了,可是代碼仍是要上一下的。java

<form action="http://baidu.com" target="" id="uploadForm" enctype="multipart/form-data">
  <input id="file" type="file" name="file"/>
  <input type="submit" name="submit" id="submit" value="upload" />
</form>

由於咱們這裏要上傳文件,因此enctype的值爲multipart/form-data。web

2.form+iframe

看到上面的代碼,form有一個target的屬性,規定在何處打開action,可能的值有ajax

  • _blank
  • _self
  • _parent
  • _top
  • framename

就不一一介紹了,咱們最關心的是最後一個值,framename,咱們將頁面放在iframe裏處理就不擔憂刷新的問題了,而後再設置一個回調就能夠處理服務端返回的參數json

html:後端

<form action="http://baidu.com"  target="" id="uploadForm" enctype="multipart/form-data">
       <input id="file" type="file" name="file"/>
       <input type="submit" name="submit" id="submit" value="upload" />
</form>

jq:數組

<script type="text/javascript">
        var form = $("#uploadForm");
            form.on("submit",function(){
                var seed = Math.floor(Math.random()*1000),
                id = "uploader-iframe" + seed,
                callback = "uploader-cb" + seed,
                iframe = $("<iframe id='"+id+"' name='"+id+"' style='display:none'></iframe>"),
                url = form.attr("action");
                form.attr("target",id).append(iframe).attr("action",url+"?iframe="+callback);
                window[callback]=function(data){
                    iframe.remove();
                    form.removeAttr("target");
                    form.attr("action",url);
                    window[callback] = undefined;
                }
            })
        </script>

有沒有以爲和jsonp的方式有點像,可是這裏不須要動態建立script標籤來調用,由於iframe原本就是一個頁面,只須要服務端返回調用方法和數據在iframe頁面就ok了瀏覽器

服務端返回:緩存

<script type="text/javascript">
window.top.window[callback](data)
</script>

callback是咱們事前約定好並傳給服務器的參數,data爲服務器返回的數據。

還有一種拿數據的方法,不經過後端回調

iframe.on("load",function(){
       var ifr =$(this).contents() //jq對象document
        //ifr = this.contentDocument || this.document//兼容ie
})

跟後端約定返回數據格式,而後進行操做

form+iframe這種僞異步的提交方式對文件的處理仍是無力,不能想刪就刪,預覽圖片只有先傳給後臺,後臺再返回一個線上的地址

3.HTML5之FormData、FileReader

噹噹噹。。文章的主角出現

利用FormData模擬表單數據,經過ajax進行提交,FileReader的readAsDataURL方法拿到base64地址來預覽(完美,注意兼容性)

form表單初始化FormData提交

<form action="http://baidu.com"  target="" id="uploadForm" enctype="multipart/form-data">
            <input id="file" type="file" name="file"/>
            <input type="submit" name="submit" id="submit" value="upload" />
        </form>
$.ajax({
    url: '/upload',
    type: 'POST',
    cache: false,
    data: new FormData($('#uploadForm')[0]),
    processData: false,
    contentType: false
}).done(function(res) {
}).fail(function(res) {});
  • processData設置爲false。由於data值是FormData對象,不須要對數據作處理。
  • <form>標籤添加enctype="multipart/form-data"屬性。
  • cache設置爲false,上傳文件不須要緩存。
  • contentType設置爲false。由於是由<form>表單構造的FormData對象,且已經聲明瞭屬性enctype="multipart/form-data",因此這裏設置爲false。

上傳後服務端經過file來接收文件流。

 經過FormData對象append方法來添加

<div id="uploadForm">
    <input id="file" type="file"/>
    <button id="upload" type="button">upload</button>
</div>
var formData = new FormData();
formData.append('file', $('#file')[0].files[0]);
$.ajax({
    url: '/upload',
    type: 'POST',
    cache: false,
    data: formData,
    processData: false,
    contentType: false
}).done(function(res) {
}).fail(function(res) {});

FileReader獲取DataUrl

<input multiple="multiple" id="file" type="file" name="file"/>
var reader = new FileReader();
reader.onload=function(e){
    //e.target.result爲$("#file")[0].files[0]的base64地址
}
reader.readAsDataURL($("#file")[0].files[0])

更多FormData和FileReader方法能夠去查看一下API

4.flash實現

flash的實現不在咱們討論的範圍,並且瀏覽器的支持對flash有很大的影響,如今有不少上傳組件作了低版本flash的兼容。好比webuploader、uploadify等

需求實現

 說了這麼多,最後仍是要回歸到需求上來,因爲這個需求是在移動端上,咱們天然而然就選了第三種實現方式,這裏講一下實現的思路(僞代碼)。

var formdata = new FormData(), count = 0, mId = '${model.id}', a = [];
    formdata.append("id", mId)
    $("#file").on("change",function() {//file觸發change時循環files作相應的處理 if ($("#file")[0].files.length > 0) {
                            
                            for (var i = 0, j = $("#file")[0].files.length; i < j; i += 1) {

                                (function(k) {//按順序插入預覽圖片,並在數組中保存對應的files var reader = new FileReader()
                                    reader.onload = function(e) {//保證預覽順序和files數組順序一致,方便後面刪除file
                                        count += 1;
                                       a.push($("#file")[0].files[k]);
                                        $(".filelist").append("<li><p class='imgWrap'><img class='close' src='img/close.png'/><img id='"
                                                                + $("#file")[0].files[k].name
                                                                + "' class='choose-img' src='"
                                                                + e.target.result
                                                                + "'' /></p></li>");//預覽相關處理
$(".swiper-wrapper").append("<div class='swiper-slide'><img id='"
                                            + $("#file")[0].files[k].name
                                            + "' class='choose-img' src='"
                                            + e.target.result
                                            + "'' /></div>");//點擊查看大圖相關處理
                                    }
                                    
                                    
                                    reader.readAsDataURL($("#file")[0].files[i]);
                                })(i);

                            }
                            
                        }
                    });
    $(document).on("click", ".close", function() {//圖片刪除處理,處理files數組,更新count var $this = $(this);
        a.splice($this.parents("li").index(), 1);
        $(".swiper-slide").eq($this.parents("li").index()).remove();//若是考慮複用,這個index能夠優化下
        count -= 1;
        $this.parents("li").remove();
        $("#jsUpload").show();
    })
    $("#jsUploadBtn").on("click", function() {//上傳時,將files數組循環append進FromData進行ajax提交 for (var i = 0, j = a.length; i < j; i += 1) {
            formdata.append("file", a[i])
        }
        $.ajax({
            url : '',
            type : 'POST',
            cache : false,
            data : formdata,
            processData : false,
            contentType : false
        }).done(function(data) {
            if (data == 'error') {
                $(".flie-toast").addClass("hide");
                toast("上傳失敗,請聯繫管理員!");
            } else if (data == 'no') {
                $(".flie-toast").addClass("hide");
                toast("您沒有參與比賽,不容許上傳截圖");
            } else if (data == 'yes') {
                $(".flie-toast").addClass("hide");
                toast("上傳成功");
                setTimeout(function() {
                    window.location.href = "";
                }, 2000);
            } else {
                $(".flie-toast").addClass("hide");
                toast("上傳失敗,請聯繫管理員!");
            }

        }).fail(function(res) {
        });

    })

雖然FormData對象有一個delete的方法,可是如今瀏覽器的支持率堪憂啊,因此只有曲線救國了。

我的知識的寬度和廣度畢竟有限,如文章有什麼疏漏和錯誤的地方,歡迎你們留言指出。

相關文章
相關標籤/搜索