JQuery事件模型并防止重复处理程序

Mr *_* AH 33 javascript jquery events triggers bind

我再次想要使用$("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;
    }
Run Code Online (Sandbox Code Playgroud)

这是一种非常粗暴的方式,我觉得,但似乎工作.我只是在绑定之前执行以下操作:

if (!HandlerExists("test", "theMethod")) {
    $(document).bind("test", theMethod);
}
Run Code Online (Sandbox Code Playgroud)

有没有人有更优雅的解决方案?例如,有没有办法检查特定的脚本是否已加载?所以我可以使用getScript()在第一次加载时从子页面加载js,然后根本不加载它在后续加载(并且只是触发一个触发器,由他预先存在的js处理).

小智 52

使用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!
Run Code Online (Sandbox Code Playgroud)



答案示例:(详细说明)


首先让我们创建一个绑定的示例元素.我们将使用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!'); }
Run Code Online (Sandbox Code Playgroud)

将exampleOne绑定到单击:

$('#button').bind('click', exampleOne); // bind example one to "click" 
Run Code Online (Sandbox Code Playgroud)

现在,如果用户点击按钮或拨打$('#button').触发('点击'),您将收到警报"One Fired!";

将exampleTwo 绑定到click的命名空间: "name是任意的,我们将使用myNamespace2"

$('#button').bind('click.myNamespace2', exampleTwo);
Run Code Online (Sandbox Code Playgroud)

关于这个很酷的事情是,我们可以触发"click",这将触发exampleOne()和exampleTwo(),或者我们可以触发"click.myNamespace2",它只会触发exampleTwo()

将exampleThree 绑定到click的命名空间: "再次,name是任意的,只要它与exampleTwo的命名空间不同,我们将使用myNamespace3"

$('#button').bind('click.myNamespace3', exampleThree);
Run Code Online (Sandbox Code Playgroud)

现在,如果触发'click'get,则会触发所有三个示例方法,或者我们可以定位特定的命名空间.

将所有东西放在一起以防止重复

如果我们继续像这样绑定exampleThree():

$('#button').bind('click.myNamespace3', exampleThree); 
$('#button').bind('click.myNamespace3', exampleThree);
$('#button').bind('click.myNamespace3', exampleThree);
Run Code Online (Sandbox Code Playgroud)

它们会被激活三次,因为每次调用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);
Run Code Online (Sandbox Code Playgroud)

如果触发了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);
    }
}   
Run Code Online (Sandbox Code Playgroud)

摘要:

jQuery事件命名空间允许绑定到主事件,但也允许创建和清除子命名空间,而不会影响同级命名空间或父级命名空间,这些命名空间具有非常小的创造性思维,可以防止重复绑定.

有关进一步说明:http://api.jquery.com/event.namespace/

  • 我认为有一个错误.解除绑定并将"click.myNamespace3"绑定在一行中.然后在下一行再次绑定'click.myNamespace3'.因此,当访问者点击按钮时,应该调用exampleThree()两次,而不是一次.这是证据:http://jsfiddle.net/mpr79qm8/ (4认同)

小智 24

一个很好的答案

绑定事件只有一次

copyPastedInfo:

如果你可以应用它,可能想看看event.preventDefaulttevent.stopPropagation 或者unbind和bind,每次都在这样的方法中

function someMethod()
{
  $(obj).off('click').on('click', function {});
}
Run Code Online (Sandbox Code Playgroud)


pro*_*son 7

嗯用的怎么样one()http://api.jquery.com/one/

还是我完全误解了你?

  • 它也是我的想法,但是`one`只会在每个绑定元素和处理程序注入页面时发生一次,我很确定这些处理程序应该*保持*绑定,同时所述元素在视图中. (2认同)

Mr *_* AH 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);
    }
},
Run Code Online (Sandbox Code Playgroud)

然后我只是调用它而不是bind方法!

$.mystuff.BindOnce("TheTrigger", OnTriggered)
Run Code Online (Sandbox Code Playgroud)

请注意,你不能在这里使用anon方法,因为它们只会被称为1,2,3等,检查dupes的唯一方法是使用方法上的toString(),这在复杂的应用程序中会非常慢