最近在项目中遇到了type = file change事件只执行一次的问题;在网上百度了一下发现还是有不少人遇到了同样的问题;提供了的解决方案也是五花八门;总结起来大概有3-5种吧。

 

1.html代码中onchange=xxx;指定

2.执行一次后,在绑定一次

3.执行一次后,替换原来的type-file

4.移除旧元素,生成一个一模一样的

5.利用live(现在是On)方法(其实就是事件委托)

 



下面一一验证上面的方法;并在最后给出最佳方案(现在先不验证ajax请求的场景,博客众说纷纭,让我觉得有ajax和没有ajax,上述方法是有区别的)

 

方法1:代码:

   <script>
function filechange() {
     alert("change");
}
 </script>

  <input type="file" id="Org_avatar" name="Org_avatar[]" 
                                onchange="filechange()" class="u-fileInput-small-but" />



  <input type="file" id="Org_avatar" name="Org_avatar[]" 
                                onchange="aler('aaaaaa')" class="u-fileInput-small-but" />


chromeIE8下验证,均可以触发多次。

 

方法2;执行一次后再绑定一次;

代码如下:

                 $("#Org_avatar").bind('change',filechange);
                function filechange() {
                    alert("bind change");
                     $("#Org_avatar").bind('change',filechange);
                }


 

这是有问题的;代码陷入不断的递归中执行此次数会随着点击次数的2n-1方执行;绕不过弯的动手试试;再次绑定时先解绑之前的函数,时可以达到效果的;代码如下:

 

                 $("#Org_avatar").bind('change',filechange);

                function filechange() {
                    alert("bind change");
                    //$("#Org_avatar").unbind('change',filechange);
                     $("#Org_avatar").bind('change',filechange);
                }


 

方案3

                var element = document.getElementById("Org_avatar");
                //  $("#Org_avatar").bind('change',filechange);
                 //$("#Org_avatar").change(filechange);
                element.onchange = filechange;
                function filechange() {
                    alert("bind change");
                      $("#Org_avatar").replaceWith(' <input type="file" id="Org_avatar" name="Org_avatar[]" class="u-fileInput-small-but" />')
                }

不管是,bind,change 还是原生的onchanges事件在chrome IE8下局执行一次;所以这个方法应该行不通;(其实jquerybind,change的底层实现还是原生的onchange,详情请看jquery源码,谢谢)

 


方案4,经过验证也不可行;其实很明显;你移除那个元素;在添加一个新元素;明显此时没有事件绑在这个新元素上(之前绑定的,是绑定在被替换的元素上)

 

                var element = document.getElementById("Org_avatar");
                //  $("#Org_avatar").bind('change',filechange);
                 $("#Org_avatar").change(filechange);
               // element.onchange = filechange;
                function filechange() {
                   $("#Org_avatar").remove();
                    var input = '<input type="file" id="Org_avatar" name="Org_avatar[]" index="a" class="u-fileInput-small-but"/>';
                    $("#nihao").append(input);
                }


方案5:利用on

 

这个方法使用过事件委托,或者处理过,给尚未出现的元素绑定事件(比如,一个弹窗在用户某个操作后,才显示处理;但是要求在触发弹窗的click;触发某个事件)。实现的原理很简单 ,就是事件委托。这里利用on或者live甚至是delegate;底层原理都是利用addEventListener 或者attachEvent;需要主要的是委托的元素必须是在页面上显示的,并且是该元素的祖先(一般委托在body上)

      $("body").on('change','#Org_avatar',function () {
                    alert("nihao");

       });
             
             
      var e = document.getElementById("Org_avatar");
       e.addEventListener("change",function(){//attachEvent
              alert("nihao");
       })

 

所以这个方法是行的通的。在chromeIE8下验证,均可以触发多次。

 



好了几种方案讲完了;但是感觉问题又来了;上传功能我们一般会设计ajax请求上传图片到后台服务器;但是上面几种方案的表现,好像不一样。。

下面进行验证,并说明结果。

 

方法1:验证ok

                function filechange() {
                    alert("nihao");
                           ajaxFileUpload();
    
                }

 

方法2:解绑之后,再绑定,验证ok

 

                                 $("#Org_avatar").bind('change',filechange);
                function filechange() {
                    alert("nihao");
                    ajaxFileUpload();
                    $("#Org_avatar").unbind('change',filechange);
                     $("#Org_avatar").bind('change',filechange);
                };


方法3:不可行;不知道为什么网上有些博客说这样可以;有知道为什么的告诉我一声。

方法4:不可行;不知道为什么网上有些博客说这样可以;有知道为什么的告诉我一声。

 

 $("#Org_avatar").bind('change',filechange);
                function filechange() {
                    alert("nihao");
                    ajaxFileUpload();
                   $("#Org_avatar").replaceWith(' <input type="file" id="Org_avatar" name="Org_avatar[]" class="u-fileInput-small-but" />');
                };


方法五,我已经在我们项目中使用了,所以很明显可以的。

                $("body").on('change','#Org_avatar',function () {
                    var allowImgageType = ['jpg', 'jpeg', 'png', 'gif'];
                    var file = $("#Org_avatar").val();
                    //获取大小
                    var byteSize = getFileSize('Org_avatar');
                    //获取后缀
                    if (file.length > 0) {
                        if (byteSize > 2048) {
                            alert("上传的附件文件不能超过2M");
                            return;
                        }
                        var pos = file.lastIndexOf(".");
                        //截取点之后的字符串
                        var ext = file.substring(pos + 1).toLowerCase();
                        //console.log(ext);
                        if ($.inArray(ext, allowImgageType) !== -1) {
                            ajaxFileUpload();
                        } else {
                            alert("请选择jpg,jpeg,png,gif类型的图片");
                        }
                    }
                    else {
                        alert("请选择jpg,jpeg,png,gif类型的图片");
                    }
                });


说在最后

所以在我看来,方法1,2(先解绑,再绑定),5是可行的。


方法3,4不知道是不是以讹传讹的结果,我也在求证中。


个人认为最好的方法还是利用事件委托。成本低,效果高;给不存在的元素和被隐藏的元素绑定事件,这种方案使我们最常用的。


方法1,感觉属于上世纪的东西;不解耦,不利于代码维护,可复用等等。

方法2的变种,先解绑再绑定;过程稍微复杂。

强烈推荐事件委托的形式处理类似问题。