如果立即反弹,事件处理程序不会解除绑定

时间:2015-04-21 12:34:52

标签: angularjs jqlite

我有一个简单的指令,可以呈现一个按钮。

指令的链接功能执行以下操作:

  1. 绑定' mouseenter'和' mouseleave'事件。
  2. 解开' mouseenter'和' mouseleave'事件。
  3. 绑定' mouseenter'和' mouseleave'事件再次发生。
  4. 事件处理程序将一条简单消息记录到控制台。我希望在mouseenter或mouseleave上调用一次处理程序。然而,它们被执行两次,就好像第2步从未发生过一样。

    指令的代码:

    function ButtonDirective() {
      return {
        restrict: 'E',
        template: '<button><span ng-transclude></span></button>',
        transclude: true,
        replace: true,
        link: function (scope, element, attrs) {          
          function mouseEnterHandler()  {
            console.log('mouse enter');
          }
    
          function mouseLeaveHandler() {
            console.log('mouse leave');
          }
    
          element.bind('mouseenter', mouseEnterHandler);
          element.bind('mouseleave', mouseLeaveHandler);
    
          element.unbind('mouseenter');
          element.unbind('mouseleave');
    
          element.bind('mouseenter', mouseEnterHandler);
          element.bind('mouseleave', mouseLeaveHandler);
        }
      }
    }
    

    以下的插件说明了这个问题:

    http://plnkr.co/ocXYYZ2jv09Ch7GDRaat

    有人知道它为什么会这样吗?

    更新:如果你包含jQuery而不是回到JQLite它就可以了。唉,这不是我的选择。

3 个答案:

答案 0 :(得分:1)

好吧,问题似乎位于JQLite中。如果你包含jQuery它按预期工作。

在JQLite中,bind()和unbind()函数只是JQLite.off()和on()的别名。

让我们考虑一下on()函数的代码。

on: function jqLiteOn(element, type, fn, unsupported) {
    // ...
}

此函数为各种类型的事件注册处理程序。显然,他们为“老鼠中心”做了一个例外。和&#39; mouseleave&#39;事件

if (type === 'mouseenter' || type === 'mouseleave') {
    // Refer to jQuery's implementation of mouseenter & mouseleave
    // Read about mouseenter and mouseleave:
    // http://www.quirksmode.org/js/events_mouse.html#link8

    jqLiteOn(element, MOUSE_EVENT_MAP[type], function(event) {
        var target = this, related = event.relatedTarget;
        // For mousenter/leave call the handler if related is outside the target.
        // NB: No relatedTarget if the mouse left/entered the browser window
        if (!related || (related !== target && !target.contains(related))) {
          handle(event, type);
        }
    });
}

将这些事件映射(MOUSE_EVENT_MAP [type])到&#39; mouseover&#39;并且&#39; mouseout&#39;分别

var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};

然后jqLit​​eOn(...)函数以递归方式调用自身并为这些映射事件注册一个匿名函数处理程序。之后它会注册您的鼠标中心&#39;和&#39; mouseleave&#39;事件

基本上这就是为什么事件处理程序被多次调用的原因。

解决方法是解除mouseover和mouseout事件的绑定。

element.unbind('mouseover mouseenter');
element.unbind('mouseout mouseleave');

答案 1 :(得分:0)

解除绑定时,您必须指定要取消绑定的功能:

  element.bind('mouseenter', mouseEnterHandler);
  element.bind('mouseleave', mouseLeaveHandler);

  element.unbind('mouseenter', mouseEnterHandler);
  element.unbind('mouseleave', mouseLeaveHandler);

  element.bind('mouseenter', mouseEnterHandler);
  element.bind('mouseleave', mouseLeaveHandler);

答案 2 :(得分:0)

行为是因为,每次鼠标进入目标元素或其子元素时,mouse entermouseenter触发mouseover事件。

应该是mouseoutmouseleave事件,而不是mouse enter element.bind('mouseover', mouseEnterHandler); element.bind('mouseout', mouseLeaveHandler); element.unbind('mouseover'); element.unbind('mouseout'); element.bind('mouseover', mouseEnterHandler); element.bind('mouseout', mouseLeaveHandler);

{{1}}