AngularJS指令 - 如果只在多个元素上触发事件,如何只触发一次事件?

时间:2013-07-03 04:10:27

标签: javascript angularjs angularjs-directive

这就是我目前所拥有的:

http://plnkr.co/edit/L9XqEyOtRSGHc9rqFPJX

我试图这样做,以便当我第一次按下向下键时,焦点将转移到#div2;重复动作应该将焦点移到li > div:first-child

然而,在演示中,第一次按下向下键时,焦点将直接跳至li > div:first-child,因为key-map上的#div1#div2捕获了相同的keydown事件,因此焦点一次从#div1跳到#div2,然后从#div2跳到li > div:first-child

我应该如何解决这个问题,或者更好的是,无论如何都要改进代码的结构?我不确定这些事件监听器是否正在以最佳方式附加到DOM。

2 个答案:

答案 0 :(得分:2)

您正在为每个元素的文档附加keydown处理程序。我认为stopPropagation()不会有任何好处,因为两个处理程序位于同一个元素上,它不会从文档传播,但两者仍然会触发。

我建议重新评估你是如何接近它的。你只希望带有焦点类的元素对它的选项进行评估,那么为什么不用你的指令将所有这些元素包装在一个元素中,让它只听一次并选择要处理的元素。

(plunker)

  <div key-mapped="">
    <!-- children will apply key map of element with focus class -->
    <div id="div1" class="focus" key-map="{
      40: '#div2'
    }">Hello</div>

指令:

  }).directive('keyMapped', function($rootScope) {
    return {
      restrict: 'A',
      link: function(scope, element, attr) {
        angular.element(document).bind('keydown', function(event) {
          var target = $(element).find('.focus');
          console.log('target: ' + target);

          var options = scope.$eval(target.attr('key-map'));

---- ---- EDIT

有人告诉我这是不是一个好的做法,但是你总是可以把事件处理程序放在你的指令对象上,并确保它只设置一次并将自定义事件发送到你绑定的'focus'类的元素在你的链接功能。

(plunker)

}).directive('keyMap', function($rootScope) {
  var dir = {
    onKeydown: function(event) {
      var element = document.querySelector('.focus');
      var newEvent = new CustomEvent("keyMapKeydown", {
        detail: { keyCode: event.keyCode },
        bubbles: false,
        cancelable: true
      });
      element.dispatchEvent(newEvent);
    },
    registered: false, // ensure we only listen to keydown once
    restrict: 'A',
    link: function(scope, element, attr) {
      // register listener only if not already registered
      if (!dir.registered) {
        dir.registered = true;
        angular.element(document).bind('keydown', dir.onKeydown);
      }

      var options = scope.$eval(attr.keyMap);

      // listen for custom event which will be dispatched only to the
      // element that has the 'focus' class
      element.bind('keyMapKeydown', function(event) {
        var keyCode = event.detail.keyCode;
        if (options && (keyCode in options)) {
          element.removeClass('focus');
          angular.element(document.querySelector(options[keyCode])).addClass('focus');                
          event.stopPropagation();
        }
      });
    }
  };

答案 1 :(得分:0)

您需要停止事件的传播。事件向上传播。在你的指令中添加如下内容:

$(elm).click(function (event) {                
    event.stopPropagation();
});

或者,您可以自己创建一个停止传播指令。 This SO question有很好的方法。