Ajax 文件上傳

常見異步上傳方案


  1. 使用第三方控件(Flash瘦赫,ActiveX, 瀏覽器插件等)

優(yōu)點:

  • 交互與可控性好(多文件、進(jìn)度展示蛤迎、續(xù)傳确虱、暫停)
  • 性能好(可使用底層協(xié)議通信)

缺點:
+ 需要瀏覽器安裝插件

  1. 使用隱藏的iframe模擬異步上傳

優(yōu)點:

  • 瀏覽器原生支持,不需要插件
  • 廣泛的瀏覽器兼容性

缺點:

  • 交互差替裆,體驗差校辩,上傳過程基本不可控
  • 性能差

關(guān)鍵技術(shù)點:

  1. form指定target,提交結(jié)果定向到隱藏的iframe辆童。
  2. 提交完成后宜咒,iframe中頁面與主頁面通信,通知上傳結(jié)果及服務(wù)端文件信息把鉴。

html

    <form action="/upload2" enctype="multipart/form-data" method="post" target="frm" onsubmit="loading(true);">
      <p id="upfile">
        附件: <input type="file" name="myfile" style="display: inline">
      </p>
      <p id="upbtn">
        <input class="btn btn-primary btn-sm" style="padding-left:50px;padding-right: 50px;" type="submit" value="異步上傳">
        <span id="uptxt" style="display: none">正在上傳...</span>
      </p>
    </form>

    <div id="flist" style="border:1px dotted darkgray;"></div>

script

    // 上傳完成后的回調(diào)
    function uploadFinished(fileName) {
        addToFlist(fileName);
        loading(false);
    }

    function addToFlist(fname) {
        var temp = ["<p id='" + fname + "'>",
                    fname,
            "<button onclick='delFile(\"" + fname + "\");'>刪除</button>",
                    "</p>"
        ];
        $("#flist").append(temp.join(""));
    }

    function delFile(fname) {
        console.log('to delete file: ' + fname);
        // TODO: 請實現(xiàn)
    }

    function loading(showloading) {
        if (showloading) {
            $("#uptxt").show();
        } else {
            $("#uptxt").hide();
        }
    }

node.js

    var express = require('express');
    var router = express.Router();

    var multipart = require('connect-multiparty');
    var multipartMiddleware = multipart();

    var fs = require('fs');

    router.all('/', function (req, res) {
        res.sendFile('../public/index.html');
    });

    router.post('/upload2', multipartMiddleware, function(req, res) {
        console.log(req.body);
        console.log(req.files);

        // 實際編程時故黑,一般要將臨時文件移動到目標(biāo)位置,之后刪除臨時文件
        // 課程中為簡化操作庭砍,直接將臨時文件當(dāng)成目標(biāo)文件
        var fpath = req.files.myfile.path;
        var fname = fpath.substr(fpath.lastIndexOf('\\') + 1);

        setTimeout(function() {
            var ret = ["<script>",
                "window.parent.uploadFinished('" + fname + "');",
                "</script>"];
            res.send(ret.join(""));
        }, 3000);

    });

    module.exports = router;
  1. 使用xhr level 2 純ajax異步上傳

優(yōu)點:

  • 支持H5的瀏覽器原生支持场晶,不需要插件
  • 交互性較好

缺點:

  • 受瀏覽器支持限制

關(guān)鍵過程:

  1. 創(chuàng)建FormData,放入待上傳文件

  2. 通過xhr操作將FormData發(fā)送到服務(wù)器怠缸,實現(xiàn)文件上傳

  3. 綁定progress峰搪、load、error等事件監(jiān)聽傳輸過程并在頁面顯示動態(tài)交互信息

html

    <div>
        <p id="upfile">附件: <input type="file" id="myfile" style="display: inline"></p>
        <p id="upbtn">
            <input class="btn btn-primary btn-sm" style="padding-left:50px;padding-right: 50px;" type="button" value="異步上傳" onclick="upload();">
            <span id="uptxt" style="display: none">正在上傳...</span>
            <span id="upprog"></span>
            <button id="stopbtn" style="display:none;">停止上傳</button>
        </p>
    </div>

    <div id="flist" style="border:1px dotted darkgray;"></div>

javascript

    function upload() {
        // 1.準(zhǔn)備FormData
        var fd = new FormData();
        fd.append("myfile", $("#myfile")[0].files[0]);

        // 創(chuàng)建xhr對象
        var xhr = new XMLHttpRequest();

        // 監(jiān)聽狀態(tài)凯旭,實時響應(yīng)
        // xhr 和 xhr.upload 都有progress事件概耻,xhr.progress是下載進(jìn)度使套,xhr.upload.progress是上傳進(jìn)度
        xhr.upload.onprogress = function(event) {
            if (event.lengthComputable) {
                var percent = Math.round(event.loaded * 100 / event.total);
                console.log('%d%', percent);
                $("#upprog").text(percent);
            }
        };

        // 傳輸開始事件
        xhr.onloadstart = function(event) {
            console.log('load start');
            $("#upprog").text('開始上傳');

            $("#stopbtn").one('click', function() {
               xhr.abort();
                $(this).hide();
            });

            loading(true);
        };

        // ajax過程成功完成事件
        xhr.onload = function(event) {
            console.log('load success');
            $("#upprog").text('上傳成功');

            console.log(xhr.responseText);
            var ret = JSON.parse(xhr.responseText);
            addToFlist(ret.fname);
        };

        // ajax過程發(fā)生錯誤事件
        xhr.onerror = function(event) {
            console.log('error');
            $("#upprog").text('發(fā)生錯誤');
        };

        // ajax被取消
        xhr.onabort = function(event) {
            console.log('abort');
            $("#upprog").text('操作被取消');
        };

        // loadend傳輸結(jié)束,不管成功失敗都會被觸發(fā)
        xhr.onloadend = function (event) {
            console.log('load end');
            loading(false);
        };

        // 發(fā)起ajax請求傳送數(shù)據(jù)
        xhr.open('POST', '/upload3', true);
        xhr.send(fd);
    }

    function addToFlist(fname) {
        var temp = ["<p id='" + fname + "'>",
                    fname,
            "<button onclick='delFile(\"" + fname + "\");'>刪除</button>",
                    "</p>"
                    ];
        $("#flist").append(temp.join(""));
    }

    function delFile(fname) {
        console.log('to delete file: ' + fname);
        // TODO: 請實現(xiàn)
    }

    function loading(showloading) {
        if (showloading) {
            $("#uptxt").show();
            $("#stopbtn").show();
        } else {
            $("#uptxt").hide();
            $("#stopbtn").hide();
        }
    }

node.js

    var express = require('express');
    var router = express.Router();

    var multipart = require('connect-multiparty');
    var multipartMiddleware = multipart();

    var fs = require('fs');

    router.all('/', function (req, res) {
        res.sendFile('../public/index.html');
    });

    router.post('/upload3', multipartMiddleware, function(req, res) {
        console.log(req.body);
        console.log(req.files);

        // 實際編程時鞠柄,一般要將臨時文件移動到目標(biāo)位置侦高,之后刪除臨時文件
        // 課程中為簡化操作,直接將臨時文件當(dāng)成目標(biāo)文件
        var fpath = req.files.myfile.path;
        var fname = fpath.substr(fpath.lastIndexOf('\\') + 1);

        res.json({fname: fname});
    });

    module.exports = router;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末厌杜,一起剝皮案震驚了整個濱河市奉呛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌夯尽,老刑警劉巖瞧壮,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異匙握,居然都是意外死亡咆槽,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門圈纺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來秦忿,“玉大人,你說我怎么就攤上這事蛾娶〉埔ィ” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵蛔琅,是天一觀的道長胎许。 經(jīng)常有香客問我,道長罗售,這世上最難降的妖魔是什么辜窑? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮莽囤,結(jié)果婚禮上谬擦,老公的妹妹穿的比我還像新娘切距。我一直安慰自己朽缎,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布谜悟。 她就那樣靜靜地躺著话肖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪葡幸。 梳的紋絲不亂的頭發(fā)上最筒,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天,我揣著相機(jī)與錄音蔚叨,去河邊找鬼床蜘。 笑死辙培,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的邢锯。 我是一名探鬼主播扬蕊,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼丹擎!你這毒婦竟也來了尾抑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蒂培,失蹤者是張志新(化名)和其女友劉穎再愈,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體护戳,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡翎冲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了灸异。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片府适。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖肺樟,靈堂內(nèi)的尸體忽然破棺而出檐春,到底是詐尸還是另有隱情,我是刑警寧澤么伯,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布疟暖,位于F島的核電站,受9級特大地震影響田柔,放射性物質(zhì)發(fā)生泄漏俐巴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一硬爆、第九天 我趴在偏房一處隱蔽的房頂上張望欣舵。 院中可真熱鬧,春花似錦缀磕、人聲如沸缘圈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽糟把。三九已至,卻和暖如春牲剃,著一層夾襖步出監(jiān)牢的瞬間遣疯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工凿傅, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留缠犀,地道東北人数苫。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像辨液,于是被迫代替她去往敵國和親文判。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容