我想再次使用$(“divid”)。load(...)将包含自己脚本的页面加载到div中。我面临的问题与事件有关。假设我们从父页面和我们绑定的加载页面(“猴子”)触发(“猴子”)并且只是做一个警报(“猴子绑定”)。如果多次调用相同的load方法,则会多次调用bind。现在我可以在绑定它之前取消绑定它,或者在绑定之前检查处理程序的数量,然后不绑定它以防止这种情况。这两个选项都不是可扩展的,如果我以后想要绑定到另一个“子页面”(加载到div中的页面)中的触发器。
我理想的做法是检查我要添加的处理程序是否已经存在,但我仍然想要使用匿名处理程序...(我想的最后一个请求有点问)。目前我有一个解决方法,使用预定义/命名方法,然后在绑定之前检查它。
// Found this on StackOverflow
function getFunctionName(fn)
{
var rgx = /^function\s+([^\(\s]+)/
var matches = rgx.exec(fn.toString());
return matches ? matches[1] : "(anonymous)"
}
function HandlerExists(triggerName, handlerName) {
exists = false;
if ($(document).data('events') !== undefined) {
var event = $(document).data('events')[triggerName];
if(event !== undefined)
{
$.each(event, function(i, handler) {
alert(handlerName);
if (getFunctionName(handler) == handlerName) {
exists = true;
}
});
}
}
return exists;
}
这是一种非常粗暴的方式,我觉得,但似乎工作。我只是在绑定之前执行以下操作:
if (!HandlerExists("test", "theMethod")) {
$(document).bind("test", theMethod);
}
有没有人有更优雅的解决方案?例如,有没有办法检查特定的脚本是否已加载?所以我可以使用getScript()在第一次加载时从子页面加载js,然后根本不加载它在后续加载(并且只是触发一个触发器,它将由他预先存在的js处理)。
答案 0 :(得分:50)
使用jQuery的事件命名空间防止重复绑定
实际上有几种不同的方法可以防止重复。一种是在unbind中传递原始处理程序,但如果它是一个副本而不是在内存中的同一空间中它不会解除绑定,另一种流行的方式(使用命名空间)是一种更加确定的实现方式。
这是事件的常见问题。因此,我将对jQuery事件进行一些解释,并使用命名空间来防止重复绑定。
答案:(简短而直截了当)
// bind handler normally
$('#myElement').bind('myEvent', myMainHandler);
// bind another using namespace
$('#myElement').bind('myEvent.myNamespace', myUniqueHandler);
// unbind the unique and rebind the unique
$('#myElement').unbind('myEvent.myNamespace').bind('myEvent.myNamespace', myUniqueHandler);
$('#myElement').bind('myEvent.myNamespace', myUniqueHandler);
// trigger event
$('#myElement').trigger('myEvent');
// output
myMainHandler() // fires once!
myUniqueHandler() // fires once!
答案示例:(完整详细说明)
首先让我们创建一个绑定的示例元素。我们将使用id为#button的按钮。然后创建3个可以用作处理程序的函数来绑定事件:
函数exampleOne()我们将通过单击进行绑定。 function exampleTwo()我们将绑定到click的命名空间。 函数exampleThree()我们将绑定到click的namepsace,但是解绑并绑定多次而不删除其他绑定,这样可以防止重复绑定,同时不删除任何其他绑定方法。
示例开始:(创建要绑定的元素以及一些方法作为我们的处理程序)
<button id="button">click me!</button>
// create the example methods for our handlers
function exampleOne(){ alert('One fired!'); }
function exampleTwo(){ alert('Two fired!'); }
function exampleThree(){ alert('Three fired!'); }
绑定exampleOne点击:
$('#button').bind('click', exampleOne); // bind example one to "click"
现在,如果用户点击按钮或拨打$(&#39;#按钮&#39;)。触发(&#39;点击&#39;),您将收到警报&#34; One Fired!&#34 ;;
将exampleTwo绑定到click的命名空间:&#34; name是任意的,我们将使用myNamespace2&#34;
$('#button').bind('click.myNamespace2', exampleTwo);
关于这个很酷的事情是,我们可以触发&#34;点击&#34;这将触发exampleOne()和exampleTwo(),或者我们可以触发&#34; click.myNamespace2&#34;这只会触发exampleTwo()
将exampleThree绑定到click的命名空间:&#34;再次,name是任意的,只要它与exampleTwo的命名空间不同,我们将使用myNamespace3&#34 ;
$('#button').bind('click.myNamespace3', exampleThree);
现在,如果点击&#39; get触发所有三个示例方法都会被触发,或者我们可以定位特定的命名空间。
全力以赴防止重复
如果我们继续像这样继续绑定exampleThree():
$('#button').bind('click.myNamespace3', exampleThree);
$('#button').bind('click.myNamespace3', exampleThree);
$('#button').bind('click.myNamespace3', exampleThree);
他们会被解雇三次,因为每次调用bind时都会将其添加到事件数组中。所以,真的很简单。只需在绑定之前取消绑定该命名空间,如下所示:
$('#button').unbind('click.myNamespace3').bind('click.myNamespace3', exampleThree);
$('#button').bind('click.myNamespace3', exampleThree);
$('#button').unbind('click.myNamespace3').bind('click.myNamespace3', exampleThree);
$('#button').bind('click.myNamespace3', exampleThree);
$('#button').unbind('click.myNamespace3').bind('click.myNamespace3', exampleThree);
$('#button').bind('click.myNamespace3', exampleThree);
如果触发了click函数,则exampleOne(),exampleTwo()和exampleThree()只会被触发一次。
将所有内容整合在一个简单的函数中:
var myClickBinding = function(jqEle, handler, namespace){
if(namespace == undefined){
jqEle.bind('click', handler);
}else{
jqEle.unbind('click.'+namespace).bind('click.'+namespace, handler);
}
}
<强>要点:强>
jQuery事件命名空间允许绑定到主事件,但也允许创建和清除子命名空间,而不会影响同级命名空间或父级命名空间,这些命名空间具有极少的创造性思维,可以防止重复绑定。
答案 1 :(得分:23)
来自
的优秀答案<强> copyPastedInfo 强>:
如果您可以申请,可能需要查看event.preventDefaultt和event.stopPropagation 或者在
之类的方法中每次取消绑定和绑定function someMethod()
{
$(obj).off('click').on('click', function {});
}
答案 2 :(得分:7)
嗯,使用one()
怎么样? http://api.jquery.com/one/
或者我完全误解了你?
答案 3 :(得分:6)
这不是一个完整的答案,但我很快就找到了如何以最小的更改修复我的所有代码。在我的“基础”js类中(这是一个在每个页面上用于按类名等标准按钮连接的对象)我添加了以下方法来检查欺骗处理程序:
BindOnce: function(triggerName, fn) {
function handlerExists(triggerName, theHandler) {
function getFunctionName(fn) {
var rgx = /^function\s+([^\(\s]+)/
var matches = rgx.exec(fn.toString());
return matches ? matches[1] : "(anonymous)"
}
exists = false;
var handlerName = getFunctionName(theHandler);
if ($(document).data('events') !== undefined) {
var event = $(document).data('events')[triggerName];
if (event !== undefined) {
$.each(event, function(i, handler) {
if (getFunctionName(handler) == handlerName) {
exists = true;
}
});
}
}
return exists;
}
if (!handlerExists(triggerName, fn)) {
$(document).bind(triggerName, fn);
}
},
然后我只是调用它而不是bind方法!
$.mystuff.BindOnce("TheTrigger", OnTriggered)
请注意,你不能在这里使用anon方法,因为它们只会被称为1,2,3等,并且检查dupes的唯一方法是使用方法上的toString(),这在一个复杂的应用程序
答案 4 :(得分:1)
大约一百年太晚了,但是如果你不使用匿名函数,你可以通过首先使用unbind来更简单地做到这一点:
$.fn.eventWillOnlySubscribeOnce = function () {
return this.each(function () {
var oneHandler = (function () {
HANDLER CODE
});
$(this).unbind("submit", oneHandler);
$(this).bind("submit", oneHandler);
});
};
此实现适用于Firefox 4,但不适用于许多其他浏览器 - 因为每次都会创建新的处理程序变量,因此unbind无法找到解除绑定的匹配处理程序。将处理程序移动到父作用域中可以解决问题:即
var oneHandler = (function () {
HANDLER CODE
});
$.fn.eventWillOnlySubscribeOnce = function () {
return this.each(function () {
$(this).unbind("submit", oneHandler);
$(this).bind("submit", oneHandler);
});
};
据推测,Firefox正在做一些聪明的优化,这意味着处理程序在某个地方保持为常量变量,因为它永远不会改变。