关于type=file;事件只执行一次的问题
最近在项目中遇到了type=filechange事件只执行一次的问题;在网上百度了一下发现还是有不少人遇到了同样的问题;提供了的解决方案也是五花八门;总结起来大概有3-5种吧。
1.html代码中onchange=xxx;指定
2.执行一次后,在绑定一次
3.执行一次后,替换原来的type-file
4.移除旧元素,生成一个一模一样的
5.利用live(现在是On)方法(其实就是事件委托)
下面一一验证上面的方法;并在最后给出最佳方案(现在先不验证ajax请求的场景,博客众说纷纭,让我觉得有ajax和没有ajax,上述方法是有区别的)
方法1:代码:
<script>functionfilechange(){alert("change");}</script><inputtype="file"id="Org_avatar"name="Org_avatar[]"onchange="filechange()"class="u-fileInput-small-but"/><inputtype="file"id="Org_avatar"name="Org_avatar[]"onchange="aler('aaaaaa')"class="u-fileInput-small-but"/>
在chrome和IE8下验证,均可以触发多次。
方法2;执行一次后再绑定一次;
代码如下:
$("#Org_avatar").bind('change',filechange);functionfilechange(){alert("bindchange");$("#Org_avatar").bind('change',filechange);}
这是有问题的;代码陷入不断的递归中执行此次数会随着点击次数的2的n-1方执行;绕不过弯的动手试试;再次绑定时先解绑之前的函数,时可以达到效果的;代码如下:
$("#Org_avatar").bind('change',filechange);functionfilechange(){alert("bindchange");//$("#Org_avatar").unbind('change',filechange);$("#Org_avatar").bind('change',filechange);}
方案3
varelement=document.getElementById("Org_avatar");//$("#Org_avatar").bind('change',filechange);//$("#Org_avatar").change(filechange);element.onchange=filechange;functionfilechange(){alert("bindchange");$("#Org_avatar").replaceWith('<inputtype="file"id="Org_avatar"name="Org_avatar[]"class="u-fileInput-small-but"/>')}
不管是,bind,change还是原生的onchanges事件在chromeIE8下局执行一次;所以这个方法应该行不通;(其实jquery的bind,change的底层实现还是原生的onchange,详情请看jquery源码,谢谢)
方案4,经过验证也不可行;其实很明显;你移除那个元素;在添加一个新元素;明显此时没有事件绑在这个新元素上(之前绑定的,是绑定在被替换的元素上)
varelement=document.getElementById("Org_avatar");//$("#Org_avatar").bind('change',filechange);$("#Org_avatar").change(filechange);//element.onchange=filechange;functionfilechange(){$("#Org_avatar").remove();varinput='<inputtype="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");});vare=document.getElementById("Org_avatar");e.addEventListener("change",function(){//attachEventalert("nihao");})
所以这个方法是行的通的。在chrome和IE8下验证,均可以触发多次。
好了几种方案讲完了;但是感觉问题又来了;上传功能我们一般会设计ajax请求上传图片到后台服务器;但是上面几种方案的表现,好像不一样。。
下面进行验证,并说明结果。
方法1:验证ok
functionfilechange(){alert("nihao");ajaxFileUpload();}
方法2:解绑之后,再绑定,验证ok
$("#Org_avatar").bind('change',filechange);functionfilechange(){alert("nihao");ajaxFileUpload();$("#Org_avatar").unbind('change',filechange);$("#Org_avatar").bind('change',filechange);};
方法3:不可行;不知道为什么网上有些博客说这样可以;有知道为什么的告诉我一声。
方法4:不可行;不知道为什么网上有些博客说这样可以;有知道为什么的告诉我一声。
$("#Org_avatar").bind('change',filechange);functionfilechange(){alert("nihao");ajaxFileUpload();$("#Org_avatar").replaceWith('<inputtype="file"id="Org_avatar"name="Org_avatar[]"class="u-fileInput-small-but"/>');};
方法五,我已经在我们项目中使用了,所以很明显可以的。
$("body").on('change','#Org_avatar',function(){varallowImgageType=['jpg','jpeg','png','gif'];varfile=$("#Org_avatar").val();//获取大小varbyteSize=getFileSize('Org_avatar');//获取后缀if(file.length>0){if(byteSize>2048){alert("上传的附件文件不能超过2M");return;}varpos=file.lastIndexOf(".");//截取点之后的字符串varext=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的变种,先解绑再绑定;过程稍微复杂。
强烈推荐事件委托的形式处理类似问题。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。