2013-07-03 24 views
0

這是我目前有:AngularJS指令 - 如何讓一個事件只觸發一次,否則會觸發多個元素?

http://plnkr.co/edit/L9XqEyOtRSGHc9rqFPJX

我試圖讓這個當我按下首次向下鍵,焦點將移動到#div2;重複該行動應該將焦點移至li > div:first-child

在演示然而,在第一次下鍵被按下時,焦點將跳轉到li > div:first-child直接,因爲無論在#div1#div2key-map捕獲時的相同keydown事件,所以進行焦點跳躍從#div1#div2然後#div2li > div:first-child一氣呵成。

我應該如何解決這個問題,或者更好的方法是改善代碼的結構?我不確定那些事件偵聽器是否以最佳方式附加到DOM。

回答

0

您需要停止事件的傳播。事件向上傳播。在你的指令中加入如下內容:

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

或者,你可以自己創建一個停止傳播指令。 This SO question有很好的做法。

2

您正在爲文檔中的每個元素附加​​處理程序。我不認爲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')); 

---- ----編輯

有人讓我知道,如果它不是一個很好的做法,但您始終可以將事件處理程序放在您的指令對象上,並確保它只設置一次並將自定義事件發送到鏈接函數中綁定的「焦點」類的元素。

(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(); 
     } 
     }); 
    } 
    }; 
+0

是否有可能僅附加一個事件偵聽器keydown事件不使用包裝「keyMapped」指令? – Kay