因此,如果我有一个 100 li 的 ul,每个 li 中是否应该有 ng-clicks,或者有没有办法将事件绑定到 ul 并将其委托给 li 的那种 jquery 做什么?这会更好还是更糟?我们有 100 个事件,还是最终只是一个事件?
4 回答
似乎 Angular 不使用中继器进行事件委托。有人在 github 上打开了一个关于它的问题。争论的焦点是它是否真的能带来更好的性能。
可能有一种解决方法,但它需要 jQuery。它包括创建一个用于父元素的特殊指令,并在其 dom 节点上注册监听器。
这是一个示例,它传递了一个函数名称,当单击子节点时要调用它,还传递了一个选择器以帮助识别要侦听的子节点。由于 Angular 的 jquery 实现只为我们提供了bind
方法 - 仅限于将事件侦听器注册到实际元素 - 我们需要加载 jQuery 才能访问on
ordelegate
方法。
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);
});
}
};
});
Plunker:http ://plnkr.co/edit/yWCLvRSLCeshuw4j58JV?p=preview
注意:可以使用隔离作用域将函数委托给指令{fun: '&'}
,这值得一看,但这会增加复杂性。
根据 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 方法,因为我从更复杂的应用程序中提取了它。
从上面的 BradGreens 的 delegateClicks 开始,我改编了一些来自 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);
});
};
});
根据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)
});
有关详细信息,请参阅