• 利用iframe无刷新上传文件的坑


    页面里经常要用到文件上传的功能,而且要求页面不刷新,先说一下原理:页面里放一个file控件和submit按钮,外面用form表单包住,给form表单加上对应的属性值,action、method、entype、name,到这一步,能上传文件了,但是这样上传文件会刷新页面,这不是我们想要的。我们要的是文件上传时不刷新页面,那么也简单,在页面里放一个iframe,设置它的宽高为0,这里有两个坑:

    1、需要设置iframe的name值与form的target属性值一样,意思就是把form表单上传文件的刷新转嫁到iframe里去了;

    2、form表单的enctype属性值必须设置成multipart/form-data,将文件转换成文件流供后端接收;

    代码如下:

    <iframe name="fileUpload"></iframe>
    <form method="post" action="xxxx" enctype="multipart/form-data" name="fileForm" target="fileUpload">
        <input type="file" class="fileInput" name="fileInput">
        <input type="submit" value="提交" />
    </form>

    页面(这里为了看到效果,就不将iframe的宽高设为0了):

    事情就这么愉快地结束了吗?当然没有,离国庆节还有那么些天,不要着急。

    到这里文件能上传了,页面也不会刷新,那么还差什么?当然是精益求精--优化啦。怎么优化?假如页面里有三个地方需要上传不同类型的文件,最好的办法肯定不是在页面里将代码copy三份,然后就这样用,这是普通开发的做法,我们可以利用js动态生成上面这些代码,需要上传文件的地方,一个函数加参数就搞定了,代码如下:

    复制代码
    /*2014年9月18日17:39:47 By 王美建*/
    function ajaxUpload(opt){
        /*
            参数说明:
            opt.frameName : iframe的name值;
            opt.url : 文件要提交到的地址;
            opt.fileName : file控件的name;
            opt.format : 文件格式,以数组的形式传递,如['jpg','png','gif','bmp'];
            opt.callBack : 上传成功后回调;
        */
        var iName=opt.frameName; //太长了,变短点
        var iframe,form;
        //创建iframe和form表单
        iframe = $('<iframe name="'+iName+'" />');
        form = $('<form method="post" style="display:none;" target="'+iName+'" action="'+opt.url+'"  name="form_'+iName+'" enctype="multipart/form-data" />');
        file = $('<input type="file" name="'+opt.fileName+'" />');
        file.appendTo(form);
        //插入body
        $(document.body).append(iframe).append(form);
        //触发浏览事件,选择文件
        file.click();
        //选中文件后,验证文件格式是否符合要求
        file.change(function(){
            //取得所选文件的扩展名
            var fileFormat=$(this).val().exec(/.[a-zA-Z]+$/)[0].substring(1);
            if(opt.format.join('-').indexOf(fileVal)!=-1){
                form.submit();//格式通过验证后提交表单;
            }else{
                iframe.remove();
                form.remove();
                alert('文件格式错误,请重新选择!');
            }
        });
        //文件提交完后
        iframe.load(function(){
            var data = $(this).contents().find('body').html();
            opt.callBack(data);
            iframe.remove();
            form.remove();
        })
    }
    复制代码
    使用方法:在页面里放一个按钮Btn,点击Btn时触发ajaxUpload方法,ajaxUpload方法内部自动创建上传所需要的元素并自动触发file.click()事件供用户选择文件,选中文件后自动验证文件格式并提交,然后返回后端返回的结果,到这里,问题解决了80%,为什么不是100%?ajaxUpload方法在IE8以上及火狐、chrome浏览器都没有问题,但在IE8及以下的浏览器上传文件会提示:没有权限!这是因为低版本的IE做了安全限制,file控件必须由用户主动点击触发选择的文件才可以上传,而不能使用js的click事件来模拟点击触发。在此我又想说,IE我~!@#¥%……&*()——……。
    办法总比困难多,既然一定要由用户点击来触发,那么直接把页面里的按钮替换成file控件吧,iframe和form还是动态创建,当用户点击file控件选择文件后,会触发file控件的chang事件,给file控件的change事件绑定ajaxUpload方法并将file控件的id传进去,ajaxUpload方法通过id获取file控件并将file控件appendTo到动态创建的form里,之后的步骤与上面无异——验证格式→提交表单→触发回调。细心的同学会发现,选择文件后,file控件会appendTo到form表单里,那页面里放file控件的地方不是空了么?并且,表单提交后,file会随着form一起被remove掉,所以,在file控件appendTo到form前,先建一个变量P将file控件的父级存起来,form表单提交之后,先将file控件appendTo回到P里面,当然,file控件appendTo到form时,file控件依然会在页面里消失,所以页面里的Btn要保留,把file控件定位在Btn上面,透明度设置成0,这样点击Btn实际上点击的是盖在上面的file控件,这样即使file控件被appendTo到form里面,用户也不会察觉到什么变化,问题迎刃而解!兼容的写法如下:
    复制代码
    /*2014年9月19日11:11:07 By 王美建*/
    function ajaxUpload(opt){ /* 参数说明: opt.id : 页面里file控件的ID; opt.frameName : iframe的name值; opt.url : 文件要提交到的地址; opt.format : 文件格式,以数组的形式传递,如['jpg','png','gif','bmp']; opt.callBack : 上传成功后回调; */ var iName=opt.frameName; //太长了,变短点 var iframe,form,file,fileParent; //创建iframe和form表单 iframe = $('<iframe name="'+iName+'" />'); form = $('<form method="post" style="display:n1one;" target="'+iName+'" action="'+opt.url+'" name="form_'+iName+'" enctype="multipart/form-data" />'); file = $('#'+opt.id); //通过id获取flie控件 fileParent = file.parent(); //存父级 file.appendTo(form); //插入body $(document.body).append(iframe).append(form); //取得所选文件的扩展名 var fileFormat=/.[a-zA-Z]+$/.exec(file.val())[0].substring(1); if(opt.format.join('-').indexOf(fileFormat)!=-1){ form.submit();//格式通过验证后提交表单; }else{ file.appendTo(fileParent); //将file控件放回到页面 iframe.remove(); form.remove(); alert('文件格式错误,请重新选择!'); }; //文件提交完后 iframe.load(function(){ var data = $(this).contents().find('body').html(); file.appendTo(fileParent); iframe.remove(); form.remove(); opt.callBack(data); }) }
    复制代码
    国际惯例,到这里,方法已经接近完美了,为什么是接近?来看一张图片:


    结构代码:
    .fileInput{ position: absolute;left: 0;top: 0;height: 30px; filter:alpha(opacity=60);opacity:0.6; background-color: transparent;}
    .btn{ 200px;height: 30px; margin: 100px auto; background-color: yellow; text-align: center; line-height: 30px; overflow: hidden; display: block; position: relative;}
    <div class="btn">选择文件<input type="file" class="fileInput" name="fileInput"></div>

    这就是放在页面里的file控件,外面用一个div包住,在IE10及以下浏览器中,用户单击红色框部分是不会弹出文件选择框的,必须单击蓝色部分或双击红色部分才行,要让蓝色部分占满外面的div怎么做到呢?用css设置宽度只会增加红色部分的宽度,这时我们会发现蓝色部分是有字的,对,可以通过设置font-size来使蓝色部分变宽,然后给file控件加上dir="rtl",这会让浏览按钮移到左边,再给.btn加上overflow:hidden,可以发现浏览按钮已经占满整个div了,如下图:


    到这里才真正完成了100%,最后,我们还可以给file控件设置accept属性,限制可选文件格式(IE8及以下不支持该属性),别忘了把file控件的透明的改为0。
  • 相关阅读:
    Leetcode 811. Subdomain Visit Count
    Leetcode 70. Climbing Stairs
    Leetcode 509. Fibonacci Number
    Leetcode 771. Jewels and Stones
    Leetcode 217. Contains Duplicate
    MYSQL安装第三步报错
    .net 开发WEB程序
    JDK版本问题
    打开ECLIPSE 报failed to load the jni shared library
    ANSI_NULLS SQL语句
  • 原文地址:https://www.cnblogs.com/li1056822533/p/6430604.html
Copyright © 2020-2023  润新知