ng ng-click事件委托

问题描述 投票:28回答:4

因此,如果我有一个带有100个li的ul,则每个li都应该有ng-clicks,或者是否可以将事件绑定到ul并将其委派给li的jquery那样?这是好是坏?我们有100个事件,还是最后只有一个事件?

angularjs angularjs-ng-repeat angularjs-ng-click
4个回答
21
投票

似乎angular并不会与中继器进行事件委派。有人打开了issue on github about it。参数是是否实际上会带来更好的性能。

可能有解决方法,但需要jQuery。它包括创建要在父元素上使用的特殊指令,并在其dom节点上注册侦听器。

这是一个示例,该函数传递了单击子节点时要调用的函数名称,还传递了一个选择器以帮助识别要收听的子节点。由于angular的jquery实现仅提供了bind方法-仅限于将事件侦听器注册到实际元素-我们需要加载jQuery才能访问ondelegate方法。

HTML

<ul click-children='fun' selector='li'>
    <li ng-repeat="s in ss" data-index="{{$index}}">{{s}}</li>
</ul>

定义的函数在控制器中定义,并且希望传递给索引

$scope.fun = function(index){
    console.log('hi from controller', index, $scope.ss[index]);      
};

该指令使用$parse将表达式转换为将从事件侦听器调用的函数。

app.directive('clickChildren', function($parse){
  return {
    restrict: 'A',
    link: function(scope, element, attrs){       
      var selector = attrs.selector;
      var fun = $parse(attrs.clickChildren);   
      element.on('click', selector, function(e){       
        // no need to create a jQuery object to get the attribute 
        var idx = e.target.getAttribute('data-index');        
        fun(scope)(idx);        
      });
    }
  };
});

柱塞:http://plnkr.co/edit/yWCLvRSLCeshuw4j58JV?p=preview


注意:可以使用隔离范围{fun: '&'}将函数委托给指令,这值得一看,但这会增加复杂性。


6
投票

在这里以jm-的示例为基础,我编写了此指令的更简洁和灵活的版本。以为我会分享。归功于jm-;)

我的版本尝试将函数名称称为$ scope [fn](e,data),或者正常失败。

它从被单击的元素中传递一个可选的json对象。这使您可以使用Angular表达式并将大量属性传递给被调用的方法。

HTML

<ul delegate-clicks="handleMenu" delegate-selector="a">
  <li ng-repeat="link in links">
    <a href="#" data-ng-json='{ "linkId": {{link.id}} }'>{{link.title}}</a>
  </li>
</ul>

Javascript

控制器方法

$scope.handleMenu = function($event, data) {
  $event.preventDefault();
  $scope.activeLinkId = data.linkId;
  console.log('handleMenu', data, $scope);
}

指令构造函数

// The delegateClicks directive delegates click events to the selector provided in the delegate-selector attribute.
// It will try to call the function provided in the delegate-clicks attribute.
// Optionally, the target element can assign a data-ng-json attribute which represents a json object to pass into the function being called. 
// Example json attribute: <li data-ng-json='{"key":"{{scopeValue}}" }'></li>
// Use case: Delegate click events within ng-repeater directives.

app.directive('delegateClicks', function(){
  return function($scope, element, attrs) {
    var fn = attrs.delegateClicks;
    element.on('click', attrs.delegateSelector, function(e){
      var data = angular.fromJson( angular.element( e.target ).data('ngJson') || undefined );
      if( typeof $scope[ fn ] == "function" ) $scope[ fn ]( e, data );
    });
  };
});

如果有人希望贡献自己的意见,我很想听听反馈。

我没有测试handleMenu方法,因为我从一个更复杂的应用程序中提取了它。


0
投票

[从上面的BradGreens的委托点击开始,我已经改编了some code from georg,这使我可以将handleMenu函数放在$ scope中更深的位置(例如$ scope.tomato.handleMenu)。

app.directive('delegateClicks', function () {
    return function ($scope, element, attrs) {
        var fn = attrs.delegateClicks.split('.').reduce(function ($scope, p) { return $scope[p] }, $scope); 
        element.on('click', attrs.delegateSelector, function (e) {
            var data = angular.fromJson(angular.element(e.target).data('ngJson') || undefined);
            if (typeof fn == "function") fn(e, data);
        });
    };
});

0
投票

根据issue on GitHub,委派事件处理没有性能优势。

仅将ng-click指令与项目$index$event一起使用:

<ul>
   <li ng-repeat="item in collection"
       ng-click="lineClicked(item, $index, $event)">
      {{item}}
   </li>
</ul>
$scope.lineClicked = function(item, index, event) {
    console.log("line clicked", item, index);
    console.log(event.target)
});

有关更多信息,请参阅

© www.soinside.com 2019 - 2024. All rights reserved.