2

ボタンをレンダリングする単純なディレクティブがあります。

ディレクティブのリンク機能は次のことを行います。

  1. 「mouseenter」および「mouseleave」イベントをバインドします。
  2. 「mouseenter」および「mouseleave」イベントのバインドを解除します。
  3. 「mouseenter」および「mouseleave」イベントを再度バインドします。

イベントのハンドラーは、単純なメッセージをコンソールに記録します。mouseenter または mouseleave でハンドラーが 1 回呼び出されることを期待します。ただし、ステップ 2 が発生しなかったかのように 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

なぜこのように振る舞うのか、誰にも分かりますか?

更新: JQLite にフォールバックする代わりに jQuery を含めると機能します。残念ながら、それは私にとって選択肢ではありません。

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);
        }
    });
}

これらのイベントは、それぞれ「mouseover」と「mouseout」にマップされます (MOUSE_EVENT_MAP[type])。

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

この動作はmouse enter、マウスがターゲット要素またはその子要素に入るたびにmouseenterイベントが発生するためです。

andの代わりにmouseoverandmouseoutイベントにする必要があります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 に答える