最近在项目中遇到了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" />
在chrome和IE8下验证,均可以触发多次。
方法2;执行一次后再绑定一次;
代码如下:
$("#Org_avatar").bind('change',filechange); function filechange() { alert("bind change"); $("#Org_avatar").bind('change',filechange); }
这是有问题的;代码陷入不断的递归中执行此次数会随着点击次数的2的n-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下局执行一次;所以这个方法应该行不通;(其实jquery的bind,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"); })
所以这个方法是行的通的。在chrome和IE8下验证,均可以触发多次。
好了几种方案讲完了;但是感觉问题又来了;上传功能我们一般会设计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的变种,先解绑再绑定;过程稍微复杂。
强烈推荐事件委托的形式处理类似问题。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。