记录小文件上传的几个例子(含进度条效果,附源码下载)

1、简单原生上传

  • 无javascript脚本、无进度条;
  • 借助iframe实现post提交后的无刷新效果;
  • jquery插件ajaxFileUpload.js的实现原型。

Html代码

    <form enctype="multipart/form-data" action="UploadFile_1" method="post" target="frameResult">
        <div class="item">
            <input id="File1" name="UserPhoto" type="file" value="" />
            <input type="submit" value="提交上传" />
            <iframe src="about:blank" id="frameResult" name="frameResult"></iframe>
        </div>
    </form>

后台代码(ASP.NET MVC)

        [HttpPost]
        public ActionResult UploadFile_1()
        {
            string result = "上传成功";
            HttpPostedFileBase file= Request.Files["UserPhoto"];
            file.SaveAs(Server.MapPath("~/Upload/")+ file.FileName);
            return Content(result);
        }

要点说明

  • 为<form>标签的action、method设值,以POST方式请求UploadFile_1方法;
  • 为<form>标签的enctype属性设值multipart/form-data,让POST请求带上<input type="file">的文件内容;
  • 为<form>标签的target属性设值frameResult,让表单的请求响应结果放到名为frameResult的iframe中显示。

 

2、纯JavaScript异步上传

  • 借助HTML5特性实现进度条、上传速度计算;
  • 无需<form>标签;
  • 不支持IE8、IE9等低版本浏览器。

JavaScript代码,因为不需要<form>标签,html也没什么内容可贴的了。

    var btnUpload = document.getElementById('btnUpload');
    btnUpload.onclick = function () {
        var fileInput = document.getElementById('File2');
        if (!fileInput.value) { return; }

        var feature = {};

        feature.fileapi = fileInput.files !== undefined;
        feature.formdata = (typeof window.FormData !== 'undefined');

        if (!feature.fileapi || !feature.formdata) {
            showMessage('当前浏览器不支持Html5,请更换高级浏览器');
            return;
        }

        var xhr = new XMLHttpRequest();
        var formData = new FormData();
        formData.append("UserPhoto", fileInput.files[0]);
        xhr.open("post", './UploadFile_2');

        //超时时间,单位是毫秒
        xhr.timeout = 60 * 1000;

        //请求结束
        xhr.onload = function (event) {
            if (xhr.status == 200) {
                showMessage("上传成功");
                return;
            }

            if (xhr.status == 404) {
                showMessage("请求路径错误");
                setProgressBar(0, 'kb/s', 'hide', '0%');
                return;
            }

            if (xhr.status == 500) {
                console.error('xhr.status == 500');
                showMessage("服务器异常");
            }
        };

        //请求异常(不包括404)
        xhr.onerror = function () {
            console.error('xhr.onerror');
            showMessage("请求发生异常");
        };

        //上传开始事件
        xhr.upload.onloadstart = function () {
            setProgressBar(0, 'kb/s', 'hide', '0%');
            lastTime = new Date().getTime();
            loadSize = 0;
        }

        //上传过程事件,间歇调用该方法用来获取上传过程中的信息
        xhr.upload.onprogress = function (event) {
            //ProgressEvent.lengthComputable:boolean类型,表示能否计算出文件长度;如果为false,那么ProgressEvent.total则为0.
            //简而言之,lengthComputabl等于true就可以做进度计算
            if (!event.lengthComputable) {
                return;
            }

            //计算上传速度,event.loaded是已发送的大小
            var now = new Date().getTime();
            var timeInterval = (now - lastTime) / 1000;
            lastTime = now;

            var sizeInterval = event.loaded - loadSize;
            loadSize = event.loaded;

            var speed = sizeInterval / timeInterval; // 单位b/s
            var bspeed = speed;
            var units = "b/s";

            if (speed / 1024 > 1) {
                speed = speed / 1024;
                units = 'kb/s';
            }
            if (speed / 1024 > 1) {
                speed = speed / 1024;
                units = 'mb/s';
            }

            speed = speed.toFixed(1);

            //计算剩余时间
            var resttime = ((event.total - event.loaded) / bspeed).toFixed(1); //单位 秒

            //计算进度百分比
            var precent = (100 * event.loaded / event.total);
            pre = Math.floor(precent);

            if (bspeed == 0) {
                //setProgressBar方法是控制进度条的,
                //这里代码没贴,在最后源码下载里有
                //四个参数:上传速度、单位、剩余时间、进度百分比
                setProgressBar(0, "b/s", 'infinity', 'noChange');
            } else {
                setProgressBar(speed, units, resttime, precent + '%');
            }
        };

        //上传终止
        xhr.upload.onabort = function () {
            console.info('xhr.upload.onabort');
        }

        //上传异常事件
        //当网络环境正常时,XMLHttpRequest.status等于404、500并不能触发upload.onerror事件
        //当网络环境异常时(offline),会触发upload.onerror事件
        xhr.upload.onerror = function () {
            console.error('xhr.upload.onerror');
        }

        //文件发送完毕事件
        //当网络环境正常时,即使XMLHttpRequest.status等于404、500,仍会被触发upload.onload事件
        //当网络环境异常时(offline),不会触发upload.onload事件
        xhr.upload.onload = function () {
            console.info('xhr.upload.onload');
        }

        //上传超时
        xhr.upload.ontimeout = function () {
            console.error('xhr.upload.ontimeout');
        }

        //发送请求
        xhr.send(formData);
    }

后台接收代码

        [HttpPost]
        public ActionResult UploadFile_2()
        {
            HttpPostedFileBase file = Request.Files["UserPhoto"];
            file.SaveAs(Server.MapPath("~/Upload/") + file.FileName);
            return Json("success");
        }

要点说明

  • 无需 <form> 标签
  • 通过判断document.getElementById('File2').files 及 window.FormData 对象是否为 undefined ,得出当前浏览器是否具备我们所需的HTML5特性;
  • FormData对象如同其名称一样以键值对形式存储表单数据;
  • 主要借助 xhr.upload 对象的两个事件 onloadstart、onprogress 实现进度条。

 

3、JQuery异步上传

  • 上个例子的Jquery版;
  • 同样需要HTML5特性支持,无法在低版本浏览器使用。
    $('#btnUpload3').click(function () {
        var $fileInput = $('#File3');
        if (!$fileInput.val()) { return; }

        var feature = {};
        //检查是否支持html5 api
        feature.fileapi = $fileInput.get(0).files !== undefined;
        feature.formdata = (typeof window.FormData !== 'undefined');

        if (!feature.fileapi || !feature.formdata) {
            showMessage('当前浏览器不支持Html5,请更换高级浏览器');
            return;
        }

        var formData = new FormData();
        formData.append("UserPhoto", $fileInput[0].files[0]);
        $.ajax({
            type: 'post',
            url: './UploadFile_2',
            data: formData,
            processData: false,//设置为false。因为data值是FormData对象,不需要对数据做处理。
            contentType: false, //设置为false。告诉jQuery不要去设置Content-Type请求头
            xhr: function () {
                var xhr = $.ajaxSettings.xhr();

                if (xhr.upload) {
                    xhr.upload.onloadstart = uploadStart;
                    xhr.upload.onprogress = uploadProgress;
                    return xhr;
                }
            },
            success: function (data, textStatus, jqXHR) {
                showMessage("上传成功");
            },
            error: function (jqXHR, textStatus, errorThrown) {
                showMessage("上传失败");
            }
        });
    });

要点说明

  • processData、contentType 设置为 false;
  • $.ajax()方法中需要为请求设置xhr赋值一个function,用于加工$.ajax()的XmlHttpRequest对象,为xhr.upload 对象的两个事件 onloadstart、onprogress 绑定处理方法,处理方法同例子2一样。最后的源码下载中会有。


4、异步表单插件jquery.form.js

  • 前三个例子的集成版,需要 <form> 标签做兼容;
  • 当浏览器不支持H5,使用例子1的方式;
  • 当浏览器支持H5,使用例子2、3的方式。

html代码

    <form id="form4" enctype="multipart/form-data" action="UploadFile_2" method="post">
        <div class="item">
            <h3>
                4、异步表单插件jquery.form.js
            </h3>

            <input id="File4" name="UserPhoto" type="file" value="" />
            <input id="btnUpload4" type="button" value="提交上传" />
        </div>
    </form>

js代码

    $('#btnUpload4').click(function () {
        var $fileInput = $('#File4');
        if (!$fileInput.val()) { return; }

        var options = {
            type: 'post',
            url: './UploadFile_2',
            success: function (data, textStatus, jqXHR) {
                showMessage("上传成功");
            },
            error: function (jqXHR, textStatus, errorThrown) {
                showMessage("上传失败");
            }
        }

        var feature = {};

        //检查是否支持html5 api
        feature.fileapi = $fileInput.get(0).files !== undefined;
        feature.formdata = (typeof window.FormData !== 'undefined');

        //如果支持html5,那么就使用进度条
        if (feature.fileapi && feature.formdata) {
            options = $.extend(options, {
                xhr: function () {
                    var xhr = $.ajaxSettings.xhr();

                    if (xhr.upload) {
                        xhr.upload.onloadstart = uploadStart;
                        xhr.upload.onprogress = uploadProgress;
                        return xhr;
                    }
                }
            });
        }

        $("#form4").ajaxSubmit(options);
    });

要点说明

  • jquery.form.js 仍然需要<form>标签作为兼容基础;
  • ajaxSubmit(options)方法中的options参数与$.ajax(options)的参数其实是同一个对象,本质就是 ajaxSubmit为  $.ajax 批了一件外套;
  • 根据上一点,我们可以使用例子3中同样的手段实现进度条。

 

源码下载:https://pan.baidu.com/s/1eWiOzvio9EVW2WlYeaKUGA

代码是用VS2015 ASP.NET MVC5写的,我把bin目录内的dll都删了,通过还原 nuget 程序包应该就能运行了。

posted @ 2018-10-29 20:37  雄介  阅读(605)  评论(0编辑  收藏  举报