我有一个要将拖放事件绑定到的页面。我希望浏览器中的整个页面都是拖放目标,因此我已将事件绑定到document
对象。不过,我的应用程序的内容是通过AJAX加载到主内容区域的,我只希望这些事件处理程序在上传页面当前可见时处于活动状态。
现在,当检索上传页面时,我正在绑定事件处理程序;但是,每次上传页面变为活动时,它都会绑定一个新的事件处理程序,这会导致当用户转到上传页面、离开然后返回时,处理程序会多次触发。我在想,如果我能让处理程序仅在尚未绑定时绑定,我就能解决这个问题。这可能吗,还是我忽略了一个更好的选择?
相关代码,如果有帮助:
$(document).bind('dragenter', function(e) {
e.stopPropagation();
e.preventDefault();
}).bind('dragover', function(e) {
e.stopPropagation();
e.preventDefault();
}).bind('drop', function(e) {
e.stopPropagation();
e.preventDefault();
self._handleFileSelections(e.originalEvent.dataTransfer.files);
});
在绑定新的事件处理程序之前,先取消绑定现有的事件处理。这对于命名空间事件[docs]:来说非常简单
$(document)
.off('.upload') // remove all events in namespace upload
.on({
'dragenter.upload': function(e) {
e.stopPropagation();
e.preventDefault();
},
'dragover.upload': function(e) {
e.stopPropagation();
e.preventDefault();
},
// ...
});
对于那些只想添加一次事件的人,避免对每个新克隆的元素使用unbind()/off()
和bind()/on()
方法。
我在代码项目网站上发现了一篇文章"用JQuery将事件绑定到尚未添加的DOM元素(作者Khrystyna Popadyuk)",该文章展示了如何只注册一次事件,甚至在元素存在之前。详细信息请阅读他的文章全文。
$("body").on("click", ".your-style", function(event) {
// your code ...
});
我写了一个"uon";(唯一的)执行此操作的jquery扩展:
$.fn.extend({
uon:function(eventname,fn) {
this.each(function() {
var alreadyexists=false;
var exevby=$._data(this,'events');
for(var xevn in exevby) {
if(xevn==eventname) {
exevby[xevn].forEach(evobj=>{
if(evobj.handler==fn) alreadyexists=true;
});
}
}
if(!alreadyexists) $(this).on(eventname,fn);
});
}
});
这意味着你可以说:
$(this).uon('click',doSomething);
$(this).uon('click',doSomething);
$(this).uon('click',doSomething);
点击时它只会做一次Something,而不是3次。
它特别适合这个对象:
var JQEvent={
ons:[],
onload:function(sel,fn) {
JQEvent.ons.push({sel:sel,fn:fn});
},
apply:function($el) {
JQEvent.ons.forEach(on => {
$el.find(on.sel).each(on.fn);
});
}
}
这意味着你可以说
JQEvent.onload('input.field',function() {
$(this).uon('click',doSomething);
}
当你点击一个input.field时,你可能想在整个系统中做点什么。
然后,当你在javascript中动态加载一些HTML或构建一些dom元素时,你就可以应用通用的:
JQuery.apply('div.new-container-element');
该元素的任何子div都将应用这些函数。