2016-03-25 111 views
3

這是我對我的指令如何在Angular中有效檢測元素點擊?

function linkFunc(scope, element, attr){ 

     // Detect Element Click Logic 
     scope.myCtrl.clickedElsewhere = {value: true}; 

     $document.on('click', function(){ 
      scope.myCtrl.clickedElsewhere.value = true; 
      scope.$apply(); 
     }); 

     element.on('click', function(){ 
      event.stopPropagation(); 
      scope.myCtrl.clickedElsewhere.value = false; 
      scope.$apply(); 
     }); 
     // End Detect Element Click Logic 

    } 

鏈接功能我們可以看到,我們使用$document.on()scope.apply,這意味着,每點擊文檔中的任何地方,我們會引發消化週期。如果我們有很多$watch觸發器,這可能會導致網頁變慢。雖然這個實現並不是每一個都很有效,但我不能想到其他方法來檢測元素單擊和關閉元素單擊來擴展和收縮我的元素。

有人可以提供一些見解嗎?

謝謝

+3

您使用'ng-click'。 – Casey

+0

@Casey嗯,但我會如何檢測元素點擊收縮?點擊時需要展開我的列表,但在用戶點擊其他元素時收縮我的列表。 ng-click似乎只能在元素點擊時檢測到。 – testing

+0

爲什麼需要在每個文檔點擊時運行'$ scope.apply()'? – charlietfl

回答

3

這將是一個很多更有效在致電$apply()之前,請檢查scope.myCtrl.clickedElsewhere.value點擊處理程序:

$document.on('click', function(){ 
    if(!scope.myCtrl.clickedElsewhere.value){ 
     scope.myCtrl.clickedElsewhere.value = true; 
     scope.$apply(); 
    } 
}); 

這樣可以防止當狀態沒有變化時不必要的摘要。


你也可以當你點擊元素上刪除此點擊監聽器,並重新塗抹:

function docHandler() { 
    if (!scope.myCtrl.clickedElsewhere.value) { 
    scope.myCtrl.clickedElsewhere.value = true; 
    scope.$apply(); 
    $document.off('click');//remove event listener completely 
    } 
} 

element.on('click', function() { 
    event.stopPropagation(); 
    scope.myCtrl.clickedElsewhere.value = false; 
    scope.$apply(); 
    $document.on('click', docHandler);// add document listener 
}); 
+0

快速的問題,'.off'可能會影響註冊'click'偵聽器的'document'的其他指令嗎? – testing

+0

是...但因爲你似乎使用jQuery,你可以像'$ document.on('click.someClickName'...'和'$ document.off('click.someClickName')'那樣命名空間事件監聽器,那麼其他的不是受影響 – charlietfl

+0

很酷,感謝您的指出。 – testing

0

您可以創建兩個指令,它們之間有父/子關係。

看看我創建的手風琴指令,我相信這是你需要的,以便弄清楚你的情況。

指令:

app.directive("accordion", function() { 
    return { 
     template: "<div ng-transclude></div>", 
     restrict: "E", 
     scope: { 
      closeall: "@" 
     }, 
     transclude: true, 
     replace: true, 
     controller: function ($scope, $element, $attrs) { 
      var itensScope = []; 

      var addItemScope = function (scope) { 
       itensScope.push(scope); 
      }; 

      var closeItens = function() { 
       if ($scope.closeall == "false") return; 
       angular.forEach(itensScope, function (scope) { 
        scope.showItem = false; 
       }); 
      } 
      return { 
       addItemScope: addItemScope, 
       closeItens: closeItens 
      }; 
     } 
    }; 
}); 
app.directive("accordionItem", function() { 
    return { 
     template: "<div><div class='item' ng-class='{itemClose: !showItem}'>{{title}}</div><div class='itemInformation' ng-show='showItem' ng-transclude></div></div>", 
     restrict: "E", 
     transclude: true, 
     replace: true, 
     scope: { 
      title: "@" 
     }, 
     require: "^accordion", 
     link: function (scope, element, attrs, ctrl, transcludeFn) { 
      ctrl.addItemScope(scope); 
      element.bind("click", function() { 
       ctrl.closeItens(); 
       scope.$apply(function() { 
        scope.showItem = !scope.showItem; 
       }); 
      }); 
     } 
    }; 
}); 

用法:

<accordion closeall="true"> 
     <accordion-item title="A"> 
      <p> 
       A 
      </p> 
     </accordion-item> 
     <accordion-item title="B"> 
      <p> 
       B 
      </p> 
     </accordion-item> 
</accordion> 

我創造了這個例子一段時間了,它在我的GitHub上可用:https://github.com/rodrigobranas/branas-angular-ui

2

你可以只創建一個點擊關閉指令

myApp.directive('clickOff', function($parse, $document) { 
    var dir = { 
    compile: function($element, attr) { 
     // Parse the expression to be executed 
     // whenever someone clicks _off_ this element. 
     var fn = $parse(attr["clickOff"]); 
     return function(scope, element, attr) { 
     // add a click handler to the element that 
     // stops the event propagation. 
     element.bind("click", function(event) { 
      event.stopPropagation(); 
     }); 
     angular.element($document[0].body).bind("click",function(event) { 
      scope.$apply(function() { 
       fn(scope, {$event:event}); 
      }); 
     }); 
     }; 
    } 
    }; 
    return dir; 
}); 

用法:

<div ng-app="myApp"> 
    <button ng-click="show=true;" click-off="show=false;"> 
     Click Me 
    </button> 
    <div class="message" ng-show="show" ng-init="show = false"> 
    You clicked on the button. Now click anywhere else... 
    </div> 
</div> 

例如: https://jsfiddle.net/oytdwyxj/

+0

這讓我感覺更有角度。 – Casey