2013-06-27 45 views
19

我正在使用现有的web应用程序,在应用程序中有各种不同形式的提交按钮,有些使用常规http post,有些定义了onClick函数,还有一些绑定了js使用元素上的类的按钮的事件处理程序。单个元素上的多个js事件处理程序

我想要做的是通过向按钮添加一个类来绑定另一个事件处理程序到这些按钮,但是我想确定的是新的事件处理程序将保证被执行,或者可以是其中一个表单提交操作发生在它意味着我的新功能没有被触及之前发生。

示例场景是,我想向这些按钮添加一个类,将它们全部绑定到一个常用的js函数,该函数只是将使用情况记录到某个api。由于表单提交已离开页面导航,是否存在未调用日志记录功能的风险?

我没有完成js开发的工作,我可以测试这100次以上,只是幸运的发射。


下面是一些代码,我已经与其中一个例子测试 - 再一次,我不问如何绑定多个事件,问题是我的规范的理解和执行是否所有的处理程序有保证。

$(document).ready(function(){ 
    $('.testingBtn').click(function() { 
     window.location.replace("http://stackoverflow.com"); 
    }); 
    $(".testingBtn").click(function(){ 
     alert('submitting!'); 
    }); 
}); 


<input class="testingBtn" type="submit" id="submitform" value="Complete Signup" /> 

如上所见,我可以绑定多个事件,在这个例子中,只是指向另一个URL,但是这可能是一个form.submit()等在我的测试警报一直烧制的第一,但我是只是在比赛条件中幸运?

+0

你使用jQuery或其他DOM和事件库吗?因为这是一个大多数这些库覆盖着极端优雅的情况。 –

+0

是的查询,虽然如果有更适合的lib会很高兴听到他们。 – rhinds

+0

'query'?你的意思是'jQuery'? –

回答

46

在JS中,您不需要确实可以控制事件处理函数被调用的顺序,但通过谨慎的委派和良好的监听器,这是可能的。

委派是事件模型最强大的功能之一。正如你可能会或可能不知道的那样:在JS中,事件被传递到dom的顶部,从它传播到应用事件的元素。因此,有理由认为,附加到全局对象的事件监听器将在之前将其处理程序调用到已附加到该元素本身的监听器。

window.addEventListener('click',function(e) 
{ 
    e = e || window.event; 
    var target = e.target || e.srcElement; 
    console.log('window noticed you clicked something'); 
    console.log(target);//<-- this is the element that was clicked 
}, false);//<-- we'll get to the false in a minute 

重要的是要注意我们实际上可以访问处理程序中的事件对象。在这种情况下,我们离开的事件对象不变,因此它只会继续向下传播到目标,在其一路下跌,则可能会是这样的满足:

document.getElementById('container').addEventListener('click', function(e) 
{ 
    e = e || window.event; 
    var target = e.target || e.srcElement; 
    if (target.tagName.toLowerCase() !== 'a' || target.className.match(/\bclickable\b/)) 
    { 
     return e;//<return the event, unharmed 
    } 
    e.returnValue = false; 
    if (e.preventDefault) 
    { 
     e.preventDefault(); 
    } 
}, false); 

现在,这个处理器将是在窗口级别的侦听器调用其助手之后调用。这次如果单击的元素没有clickable类,或者元素是链接,则此事件将更改为。这个事件被取消了,但它仍然存在。该事件仍然是免费的进一步传播下来的DOM,所以我们可能会遇到这样的:

document.getElmentById('form3').addEventListener('click',function(e) 
{ 
    e = e || window.event; 
    if (e.returnValue === false || e.isDefaultPrevented) 
    {//this event has been changed already 
     //do stuff, like validation or something, then you could: 
     e.cancelBubble = true; 
     if (e.stopPropagation) 
     { 
      e.stopPropagation(); 
     } 
    } 
}, false); 

在这里,通过调用stopPropagation,该事件被杀死。除非事件已经发生变化,否则它不能向下传播到目标。如果没有,事件对象会进一步向下移动,如同没有任何事情发生一样。

一旦到达目标节点,事件就进入第二阶段:泡泡阶段。它不是向下传播到DOM深处,而是向上爬升,到达顶层(一直到全局对象,在那里被调度...从哪里来,等等)。

在泡沫阶段,所有相同的规则适用于传播阶段,只有相反的方式。事件对象将遇到最接近目标元素的元素,最后会遇到全局对象。

There's a lot of handy, and clear diagrams for this here。我不能说比好的古怪模式更好,所以我建议你阅读他们在那里说的话。底线:在处理2个事件监听器时,将它们在不同的级别上附加以排序 - 按照您喜欢的方式对它们进行排序。

如果要保证两者都被调用,则只能停止在最后调用的处理程序中传播该事件。

当你有两个侦听器,连接到相同事件的同一个元素/对象时,我从来没有遇到过首先连接侦听器的情况,也没有首先被调用。

就是这样,我去睡觉,希望我是有道理的

+0

即使我不是那个问这个问题的人,你的回答非常方便。谢谢 –

6

jQuery使这个很简单。

$(document).on('click', '.someclass', function() { 
    doStuff(); 
}); 

$(document).on('click', '.someclass', function() { 
    doMoreStuff(); 
}); 

处理程序然后都会点击发射。 jQuery为你保留了一个handers队列。并处理与您选择的选择器相匹配的文档点击,以便无论何时创建按钮都可以触发它们。

+0

感谢Alex - js保证doStuff()和doMoreStuff()会执行完成吗?即使doStuff重定向到另一个url,doMoreStuff()总是会在它完成之前完成? (我用一个例子更新了我的问题) – rhinds

+0

@rhinds在大多数情况下是。在从页面导航的情况下,我不确定。测试它并找出! –

+0

我想补充一点,如果你的代码需要在你离开你的页面后才会出现,我会重新考虑你的方法......这似乎是一个糟糕的主意。 –

3

我/是有一个类似的问题,因为这一点。但是我不能影响/委托预先存在的'click'事件(由Wicket框架添加)的顺序。 但我仍然需要执行一个新的自定义事件,然后在之前执行框架处理的任何“点击”或“更改”事件。

幸运的是,有几个事件是按顺序实际执行的。 'ousedown'和'mouseup'恰好发生在'点击'之前。
http://en.wikipedia.org/wiki/DOM_events

$(document).on('mousedown', function (event) { 
    event = event || window.event 
    var target = event.target || event.srcElement; 
    console.log(target + ' before default event'); // Hold mouse button down to see this message in console before any action is executed 
}); 

OR

$(document).on('mouseup', function (event) { 
    event = event || window.event 
    var target = event.target || event.srcElement; 
    alert(target + ' before default event'); // You may not notice this event fires when the page changes unless this is an alert 
}); 

这将允许例如被执行的实际事件之前进行(例如,经由AJAX)的日志记录通过(ajax)链接更改页面。

当然,您可能需要更复杂的方法来检测应该完成哪些附加事件处理,但您可以使用例如“目标”信息。 =>此脚本监视页面上的所有内容,因为这是我需要完成的。

+0

哦@维尔你绝对的传奇。我花了几天的时间寻找这个。 Materializecss sideNav函数似乎会破坏动态内容上的点击事件。适用于最初加载的内容,但是我使用$(document).on('click','。second-class-to-hook-for-for-for-own-function')的那些内容从未被触发。使用mouseup而不是点击,在框架启动之前执行了我的其他功能,并且实际上改善了用户的视速。 THANK YOU! – Solvision

相关问题