点击到处,但在这里事件
想知道我将如何执行“点击任何地方,但在这个元素”事件。
我有一些你可以比较文件浏览器中的文件列表。 您可以select某些元素,但是如果在元素控制器外部单击,则需要取消select所有元素。
添加了一个截图,使其更清晰。 所以我想要做的是,如果我点击任何地方,但在语言元素,它应该触发一个事件。
更新
澄清我不问我怎么可以用jQuery做到这一点。
编辑:在这个旧的,旧的答案有几个问题。
*另外:标记社区Wiki(对我来说没有积分),因为错误
-
N要求对指令进行N次使用。 对于使用匹配expression式的相同范围内的使用,这可能不是理想的。
-
没有什么是撕毁事件处理者! 坏! 坏! 坏!
所以,我正在更新这个答案。 希望它不会造成任何麻烦。
更新了答案
这里有一个新的解决scheme,解决了这些问题 ……个别应用程序开发人员可能会遇到其他问题。 这只是一个如何处理这个问题的例子。
app.factory('clickAnywhereButHereService', function($document){ var tracker = []; return function($scope, expr) { var i, t, len; for(i = 0, len = tracker.length; i < len; i++) { t = tracker[i]; if(t.expr === expr && t.scope === $scope) { return t; } } var handler = function() { $scope.$apply(expr); }; $document.on('click', handler); // IMPORTANT! Tear down this event handler when the scope is destroyed. $scope.$on('$destroy', function(){ $document.off('click', handler); }); t = { scope: $scope, expr: expr }; tracker.push(t); return t; }; }); app.directive('clickAnywhereButHere', function($document, clickAnywhereButHereService){ return { restrict: 'A', link: function(scope, elem, attr, ctrl) { var handler = function(e) { e.stopPropagation(); }; elem.on('click', handler); scope.$on('$destroy', function(){ elem.off('click', handler); }); clickAnywhereButHereService(scope, attr.clickAnywhereButHere); } }; });
原始答案(修复了事件处理程序的拆解)
你已经接近你find的一个答案,但我已经为你展示了什么是缺失的。
app.directive('clickAnywhereButHere', function($document){ return { restrict: 'A', link: function(scope, elem, attr, ctrl) { var elemClickHandler = function(e) { e.stopPropagation(); }; var docClickHandler = function() { scope.$apply(attr.clickAnywhereButHere); }; elem.on('click', elemClickHandler); $document.on('click', docClickHandler); // teardown the event handlers when the scope is destroyed. scope.$on('$destroy', function() { elem.off('click', elemClickHandler); $document.off('click', docClickHandler); }); } } })
HTML
<a click-anywhere-but-here="clickedSomewhereElse()" ng-click="clickedHere()">Don't Click Me!</a>
目前接受的答案的问题是,如果多次使用该指令,每个具有指令附加的DOM元素将防止冒泡(因此,如果您有两个元素,并且您单击其中任何一个,则两者的callback将是阻止)。
编辑 – 避免jQuery,清理 – 在你的作用域上定义一个函数,并直接传递给这个指令(没有括号),事件将在调用时传递给它。
app.directive('clickAnywhereButHere', function($document, $parse) { return { restrict: 'A', scope: { callback : '=clickAnywhereButHere' }, link: function(scope, element, attr, ctrl) { var handler = function(event) { if (!element[0].contains(event.target)) { scope.callback(event); } }; $document.on('click', handler); scope.$on('$destroy', function() { $document.off('click', handler); }); } } });
HTML中的用法
<a click-anywhere-but-here="myFunction"></a>
控制器中的用法
$scope.myFunction = function (event) { ... }
–
注意,你可能需要用scope.$apply()
来包装scope.callback(event)
scope.$apply()
如果你有很多需要这个指令的元素,这里是另一个性能优化的解决scheme。 (例如一个有100多行的列表,每个都有这个指令)
这将始终只包含一个$文档侦听器
angular.module('app').directive('clickElsewhere', ['$document', function ($document) { return { link: function postLink(scope, element, attr) { var elsewhere = true; element.on('click', function(e) { elsewhere = false; $document.off('click', clickElsewhere); $document.on('click', clickElsewhere); }); var clickElsewhere = function() { if (elsewhere) { scope.$apply(attr.clickElsewhere); $document.off('click', clickElsewhere); } elsewhere = true; }; } }; }]);
Max Bates的解决scheme的问题是所有的指令都为$ document.on('click',function(…))添加一个监听器。 导致性能问题的事件。
接受答案的问题已经说明了Max Bates。
在这个博客文章findanwser。
指示:
app.directive('documentClick', function ($document, $parse) { var linkFunction = function ($scope, $element, $attributes) { var scopeExpression = $attributes.documentClick; var invoker = $parse(scopeExpression); $document.on('click', function (event) { $scope.$apply(function () { invoker($scope, { $event: event }); }); }); }; return linkFunction; });
控制器:
app.controller('PageCtrl', function ($scope) { $scope.click = function (e) { if (!$(e.target).is('.language')) { //do stuff } }; });
视图:
<body ng-controller='PageCtrl' document-click='click($event)'></body>
这是一个基于Max的解决scheme的变体,但在标准的angular度事件指令方面更自然:
app.directive('clickOut', function($document) { return { restrict: 'A', scope: { clickOut: '&' }, link: function (scope, element) { var handler = function(event) { if (!element[0].contains(event.target)) { scope.$apply(function () { scope.clickOut({ $event : event }); }); } }; $document.on('click', handler); scope.$on('$destroy', function() { $document.off('click', handler); }); } }; });
用法
<div click-out="myFunction()"></div>
通过点击事件
<div click-out="myFunction($event)"></div>
最简单的方法是检查元素的作用域$ id和clickScope。$ id(click事件的目标作用域$ id)。
link: function(scope, element, attrs) { //close element when mouse click outside var documentClickHandler = function(event) { var clickScope = angular.element(event.target).scope(); if (clickScope.$id != scope.$id) { //clickScope.$parent is for clicking on the directive children scope if(clickScope.$parent === null || clickScope.$parent.$id != scope.$id){ //Click everywhere but on this element //Do anything you want here, like close your element; } } }; $document.on('click', documentClickHandler); scope.$on('$destroy', function() { $document.off('click', documentClickHandler); }); }
这个解决scheme的好处:
- 你只需要绑定一个
$(document)
。 事件的其他发射将取决于$emit
范围事件。 - 您可以使用expression式
click-elsewhere="show=false"
,并click-elsewhere="fn()"
,感谢$parse
。
码:
// broadcast click event within AppCtrl app.controller('AppCtrl', function($rootScope) { $(document).on('click', function(e) { // use $emit so the event stays inside $rootScope $rootScope.$emit('click', {target: e.target}); }; }; app.directive('clickElsewhere', function($rootScope) { return { restrict: 'A', compile: function($element, attr) { // store fn in compile so it only execute once var fn = $parse(attr['clickElsewhere']); return function(scope, element) { var offEvent = $rootScope.$on('click', function(event, target) { if ( (element.find($(target)).length) || element.is($(target)) ) return; scope.$apply(function() { fn(scope, {$event: event}); }); }); scope.$on('$destroy', offEvent); }; } };
HTML中的用法
-
click-elsewhere="fn()"
-
click-elsewhere="show=false"
它可能有点偏离上下文,但是你可以对所有select的项目进行分类(例如“select”),当用户点击“不要点击这里”元素时,可以将当前分类为“select”的所有项目解密,分类具体元素…