关于js异步上传文件

好久没登录博客园了,今天来一发分享。

  最近项目里有个需求,上传文件(好吧,这种需求很常见,这也不是第一次遇到了)。当时第一想法就是直接用form表单提交(原谅我以前就是这么干的),不过表单里不仅有文件还有别的信息需要交互,跟后端商量后决定文件单独上传,获取到服务器端返回的文件地址在和表单一起提交。这里就需要异步上传文件。

  在网上扒了扒相关的内容,发现还真不少,阮一峰老师的这篇文章(文件上传的渐进式增强)就介绍的很具体,下面就谈谈自己在实战中遇到的一些问题的感受吧。

  先看看效果,实现了哪些功能

  (好吧,就一个按钮而已,搞得神神秘秘,嘿嘿)

  

1

<button type="button" class="btn" @click="upload">点击上传文件</button>

  给按钮绑定了一个点击事件,下面看看点击事件方法里做了什么

methods: {
        upload: function(){
            myUpload({
                url: window.location.protocol + '//' + window.location.host + '/crm/upload',
                maxSize: 10,
                beforeSend: function(file){

                },
                callback: function(res){
                    var data = JSON.parse(res);
                    pageCont.attachmentUrl = data.url;
                },
                uploading: function(pre){
                    pageCont.uploadCont.display = 'block';
                    pageCont.uploadStyle.width = pre * 2 + 'px';
                    pageCont.pre = pre;
                }
            });
        }
}

  按钮绑定的点击事件执行了upload方法,在upload方法里调用了一下myUpload方法,并传递了一些配置信息进去,稍后说下这些配置信息。先看看myUpload的具体实现:

  初始化了一个FormData对象和一个XMHttpResquest对象,创建一个type为file的input,并触发一次该input的click,如下

var fd = new FormData(),
        xhr = new XMLHttpRequest(),
        input;
input = document.createElement('input');
input.setAttribute('id', 'myUploadInput');
input.setAttribute('type', 'file');
input.setAttribute('name', 'file');
document.body.appendChild(input);
input.style.display = 'none';
input.click();

  监听刚才创建的input的change事件,并作在里面做相应处理

input.onchange = function(){
        if(!input.value){return;}
        if(option.maxSize &&  input.files[0].size > option.maxSize * 1024 * 1024){
            dialog({
                title: '提示',
                content: '请上传小于'+option.maxSize+'M的文件',
                okValue: '确定',
                ok: function () {}
            }).showModal();
            return;
        }
        if(option.beforeSend instanceof Function){
            if(option.beforeSend(input) === false){
                return false;
            }
        }
        fd.append('file', input.files[0]);
        xhr.open('post', option.url);
        xhr.onreadystatechange = function(){
            if(xhr.status == 200){
                if(xhr.readyState == 4){
                    if(option.callback instanceof Function){
                        option.callback(xhr.responseText);
                    }
                }
            }else{
                if(!(dialog.get('uploadfail'))){
                    dialog({
                        id: 'uploadfail',
                        title: '提示',
                        content: '上传失败',
                        okValue: '确定',
                        ok: function () {}
                    }).showModal();
                }
            }
        }
        xhr.upload.onprogress = function(event){
            var pre = Math.floor(100 * event.loaded / event.total);
            if(option.uploading instanceof Function){
                option.uploading(pre);
            }
        }
        xhr.send(fd);
    }

  解释下上面的代码。input的change事件触发后,首先判断了下当前是否选择了文件

if(!input.value){return;}

  一开始我是没做这个判断的,在后来的测试过程中发现,当上传一次文件后,再次点击按钮上传,打开文件选择框,然后不选择文件,而是点击取消按钮,change事件也触发了,导致后面的代码也会执行,显然这不合理,故加了这个判断。

  然后限制了下上传文件的大小(这样的事能够前端处理就不要交给服务端来验证了),当文件大小超过最大限制,就会弹框提示

if(option.maxSize &&  input.files[0].size > option.maxSize * 1024 * 1024){
            dialog({
                title: '提示',
                content: '请上传小于'+option.maxSize+'M的文件',
                okValue: '确定',
                ok: function () {}
            }).showModal();
            return;
        }

  然后加了一个文件上传前的操作,可以在文件上传前做一些处理,如进度条的显示,图片预览等等

       if(option.beforeSend instanceof Function){
            if(option.beforeSend(input) === false){
                return false;
            }
        }   

 

  接下来将文件append到formData对象里,使用字段名‘file’,该字段名是服务端接收文件时使用的字段名

fd.append('file', input.files[0]);

  然后就是使用XMLHttpRequest对象向服务端发送数据了

        xhr.open('post', option.url);
        xhr.onreadystatechange = function(){
            if(xhr.status == 200){
                if(xhr.readyState == 4){
                    if(option.callback instanceof Function){
                        option.callback(xhr.responseText);
                    }
                }
            }else{
                if(!(dialog.get('uploadfail'))){
                    dialog({
                        id: 'uploadfail',
                        title: '提示',
                        content: '上传失败',
                        okValue: '确定',
                        ok: function () {}
                    }).showModal();
                }
            }
        }
        xhr.upload.onprogress = function(event){
            var pre = Math.floor(100 * event.loaded / event.total);
            if(option.uploading instanceof Function){
                option.uploading(pre);
            }
        }
        xhr.send(fd);    

  在向服务端发送数据时,使用了监听了一下progress事件,主要是为了进行上传进度的显示,上述代码中,

var pre = Math.floor(100 * event.loaded / event.total);

  获取上传的百分比,能够拿到这个值,页面上就可以展示各种各样的上传进度效果了。

 

  差不多介绍完了,下面补充一下使用中遇到的问题:

  问题一:文件在上传的过程中,使用JSON.parse()序列化服务端返回的json字符串报错(傻啊,文件还在上传,服务端怎么会返回数据啊)。

事情是这样的,一开始,我在readystatechange里只监听了状态码是否是200,如果是就说明通了,然后执行回调,在回调里处理服务端返回的数据,但是通了不一定代表服务端已经返回了数据,所以就出现了上面的错误,所以后来在判断了status是否为200后,还判断了readyState,以确保服务端已处理完毕并返回数据在执行回调

            if(xhr.status == 200){
                    if(option.callback instanceof Function){
                        option.callback(xhr.responseText);
                    }
            }    

  问题二:重复创建input。每次点击按钮上传文件后,页面都会多一个type=file的input感觉不是很好(个人癖好吧),所以对最开始的初始化代码做了下优化,判断当前页面是否存在刚才创建的input,存在就直接使用,不存在就创建,如下

    if(document.getElementById('myUploadInput')){
        input = document.getElementById('myUploadInput');
    }else{
        input = document.createElement('input');
        input.setAttribute('id', 'myUploadInput');
        input.setAttribute('type', 'file');
        input.setAttribute('name', 'file');
        document.body.appendChild(input);
        input.style.display = 'none';
    }

 

好了,就这么多了。看看效果

 

因个人知识面有限,如有错误,还请指正。转载请注明出处,谢谢!

时间: 2024-08-01 14:43:36

关于js异步上传文件的相关文章

JQuery插件ajaxfileupload.js异步上传文件实例

这篇文章主要介绍了JQuery插件ajaxfileupload.js异步上传文件实例,本文直接给出了HTML代码和JS代码以及后台处理代码,需要的朋友可以参考下     在服务器端做文件上传的过程中,如果使用web服务器短端的上传控件去上传文件的话,会导致页面刷新一次,这样对用户的体验就不是很友好了.ajaxfileupload.js是一款jQuery的异步上传文件插件,使用简单且容易上手. 前置条件:ajaxfileupload.js文件,百度下载一个就行. JS引用:  代码如下: <scr

JQuery插件ajaxfileupload.js异步上传文件实例_jquery

在服务器端做文件上传的过程中,如果使用web服务器短端的上传控件去上传文件的话,会导致页面刷新一次,这样对用户的体验就不是很友好了.ajaxfileupload.js是一款jQuery的异步上传文件插件,使用简单且容易上手. 前置条件:ajaxfileupload.js文件,百度下载一个就行. JS引用: 复制代码 代码如下: <script src="/Content/JQueryJS/jquery-2.1.1.js"></script> <script

jQuery异步上传文件插件ajaxFileUpload详细介绍

这篇文章主要介绍了jQuery异步上传文件插件ajaxFileUpload详细介绍,本文首先讲解了ajaxFileUpload的参数.错误提示等知识,然后给出了简单使用实例和ASP.NET MVC模式下的使用实例,需要的朋友可以参考下     一.ajaxFileUpload是一个异步上传文件的jQuery插件. 传一个不知道什么版本的上来,以后不用到处找了. 语法:$.ajaxFileUpload([options]) options参数说明: 1.url 上传处理程序地址. 2,fileEl

jQuery异步上传文件插件ajaxFileUpload详细介绍_jquery

一.ajaxFileUpload是一个异步上传文件的jQuery插件. 传一个不知道什么版本的上来,以后不用到处找了. 语法:$.ajaxFileUpload([options]) options参数说明: 1.url   上传处理程序地址. 2,fileElementId   需要上传的文件域的ID,即<input type="file">的ID. 3,secureuri 是否启用安全提交,默认为false. 4,dataType 服务器返回的数据类型.可以为xml,sc

jquery实现兼容IE8的异步上传文件_jquery

案例: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>无标题文档</title> <script type="text/

jquery.form.js异步上传完图片在post表单为啥post不了

问题描述 jquery.form.js异步上传完图片在post表单为啥post不了 下面是一个post表单 @using (Ajax.BeginForm("AddNewsInfoModel", "AdminNewsList", new AjaxOptions() { HttpMethod = "post", OnSuccess = "afterAdd" }, new { id = "Form1" })) {

Ajax表单异步上传文件实例代码(包括文件域)_AJAX相关

1.起因 做前台页面时,需要调用WebAPI的Post请求,发送一些字段和文件(相当于把表单通过ajax异步发送出去,得到返回结果),然后得到返回值判断是否成功. 2.尝试 先是尝试了一下 "jQuery Form Plugin" ,这玩意就是的巨大的坑,实现他和jquery1.9.2兼容性就不是太好,好不容易把$.browser的问题解决了,发现用他上传文件得不到返回值. $("#view").submit( $("#view").ajaxSu

PHP结合jQuery插件ajaxFileUpload实现异步上传文件实例_php实例

平时用的比较多的JQuery图片上传插件是Uploadify这个插件,效果很不错,但是由于手机不支持flash,所以不得不再找一个文件上传插件来用了.后来发现ajaxFileUpload这个插件挺不错,所以就用这个插件来做异步上传文件的效果.网上也有很多对ajaxFileUpload插件的使用的文章,不过我发现没有PHP版,所以这次服务器那边的处理就使用PHP语言来处理. 一.详解ajaxFileUpload插件的语法参数 原理:ajaxfileupload是通过监听iframe的onload方

jQuery.form插件的使用及跨域异步上传文件_jquery

先说明白 这个跨域异步上传功能我们借助了Jquery.form插件,它在异步表单方面很有成效,而跨域我们会在HTTP响应头上添加 access-control-allow-method,当然这个头标记只有IE10,火狐和谷歌上支持,对于IE10以下的浏览器来说,我们就不能用这种方式了,我们需要换个思路去干这事,让服务端去重写向我们的客户端,由客户端(与文件上传页面在同域下)来返回相关数据即可. 再做事 1 Jquery.form的使用 <form method="post" ac