2

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

该指令的链接函数执行以下操作:

  1. 绑定“mouseenter”和“mouseleave”事件。
  2. 取消绑定 'mouseenter' 和 'mouseleave' 事件。
  3. 再次绑定 'mouseenter' 和 'mouseleave' 事件。

事件的处理程序将简单的消息记录到控制台。我希望在 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);
    }
  }
}

以下 plunker 说明了这个问题:

http://plnkr.co/ocXYYZ2jv09Ch7GDRaat

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

更新:如果你包含 jQuery 而不是依赖 JQLite,它就可以工作。唉,这不是我的选择。

4

3 回答 3

1

好吧,问题似乎出在 JQLite 中。如果您包含 jQuery,它会按预期工作。

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

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

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

该函数为各种类型的事件注册处理程序。显然他们为“mouseenter”和“mouseleave”事件做了一个例外。

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])到“mouseover”和“mouseout”。

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

然后 jqLit​​eOn(...) 函数递归调用自身并为这些映射事件注册一个匿名函数处理程序。之后它会注册您的“mouseenter”和“mouseleave”事件。

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

一种解决方法是同时取消绑定 mouseover 和 mouseout 事件。

element.unbind('mouseover mouseenter');
element.unbind('mouseout mouseleave');
于 2015-04-21T14:18:01.370 回答
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);
于 2015-04-21T12:43:40.113 回答
0

该行为是因为,每次mouse enter鼠标进入目标元素或其子元素时,mouseenter都会触发该事件。

它应该是mouseovermouseout事件而不是mouseleavemouse enter

  element.bind('mouseover', mouseEnterHandler);
  element.bind('mouseout', mouseLeaveHandler);

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

  element.bind('mouseover', mouseEnterHandler);
  element.bind('mouseout', mouseLeaveHandler);
于 2015-04-21T12:44:34.753 回答