我一直在寻找AngularJS的单击和双击事件处理,因为即使为我们的元素设置了ng-dblclick指令,AngularJS也只会触发ng-click事件。
以下是寻求解决方案的人的一些工作代码:
JS:
function MyController($scope) {
var waitingForSecondClick = false;
$scope.singleClickAction = function() {
executingDoubleClick = false;
if (waitingForSecondClick) {
waitingForSecondClick = false;
executingDoubleClick = true;
return $scope.doubleClickAction();
}
waitingForSecondClick = true;
setTimeout(function() {
waitingForSecondClick = false;
return singleClickOnlyAction();
}, 250); // delay
/*
* Code executed with single AND double-click goes here.
* ...
*/
var singleClickOnlyAction = function() {
if (executingDoubleClick) return;
/*
* Code executed ONLY with single-click goes here.
* ...
*/
}
}
$scope.doubleClickAction = function() {
/*
* Code executed ONLY with double-click goes here.
* ...
*/
};
}
HTML:
<div ng-controller="MyController">
<a href="#" ng-click="singleClickAction()">CLICK</a>
</div>
所以我的问题是(因为我是一名AngularJS新手):有人可以更有经验地写一些很好的指令来处理这两件事吗?
在我看来,完美的方法是改变ng-click,ng-dblclick的行为,并添加一些“ng-sglclick”指令来处理单击式代码。 不知道它是否可能,但我发现它对每个人都非常有用。
随意分享您的意见!
答案 0 :(得分:28)
你可以写自己的。我看一下角度处理点击的方式,并使用我在此处找到的代码对其进行修改:Jquery bind double click and single click separately
<div sglclick="singleClick()" ng-dblClick="doubleClick()" style="height:200px;width:200px;background-color:black">
mainMod.controller('AppCntrl', ['$scope', function ($scope) {
$scope.singleClick = function() {
alert('Single Click');
}
$scope.doubleClick = function() {
alert('Double Click');
}
}])
mainMod.directive('sglclick', ['$parse', function($parse) {
return {
restrict: 'A',
link: function(scope, element, attr) {
var fn = $parse(attr['sglclick']);
var delay = 300, clicks = 0, timer = null;
element.on('click', function (event) {
clicks++; //count clicks
if(clicks === 1) {
timer = setTimeout(function() {
scope.$apply(function () {
fn(scope, { $event: event });
});
clicks = 0; //after action performed, reset counter
}, delay);
} else {
clearTimeout(timer); //prevent single-click action
clicks = 0; //after action performed, reset counter
}
});
}
};
}])
这是一个例子
答案 1 :(得分:24)
首先要问的是为什么超时会被用来解决这些问题。本质上,它们用于使函数跳过当前事件循环的其余部分,以便执行是干净的。但是,在角度中,您实际上对摘要循环的工作原理感兴趣。它与您的经典事件处理程序几乎相同,除了一些微小的差异,这使得它非常适合用户体验。您手头上处理函数执行顺序的一些工具包括scope.$eval
,scope.$evalAsync
,scope.$apply
和scope.$applyAsync
。
我相信$apply
会启动另一个摘要循环,离开$eval
s。 $eval
将使用当前$scope
的上下文立即运行您包含的任何代码,$evalAsync
会将您的函数排入队列,以便在摘要循环结束时运行。从本质上讲,$evalAsync
是$timeout
的一个更清晰的版本,有一个很大的区别 - 第一个有上下文并存在于范围内!
这意味着您实际上可以在同一元素上处理ng-click
和ng-dblclick
。 但请注意,这仍会在双击功能之前触发单击功能。这应该足够了:
<div ng-controller="MyController">
<a href="#"
ng-click="$evalAsync(singleClickAction())"
ng-dblclick="doubleClickAction()">
CLICK
</a>
</div>
Here's a jsfiddle with the intended functionality using Angular 1.6.4
答案 2 :(得分:13)
遇到这个并且以为我会抛弃另一种选择。除了两个关键点之外,它与原始海报没有什么不同。
1)没有嵌套的函数声明。
2)我使用$ timeout。我经常使用$ timeout,即使没有延迟......特别是如果我开始承诺做其他工作。当摘要周期到来时,$ timeout将触发,这将确保应用范围内的任何数据更改。
鉴于
<img src="myImage.jpg" ng-click="singleClick()" ng-dblclick="doubleClick()">
在您的控制器中,singleClick功能如下所示:
$scope.singleClick = function () {
if ($scope.clicked) {
$scope.cancelClick = true;
return;
}
$scope.clicked = true;
$timeout(function () {
if ($scope.cancelClick) {
$scope.cancelClick = false;
$scope.clicked = false;
return;
}
//do something with your single click here
//clean up
$scope.cancelClick = false;
$scope.clicked = false;
}, 500);
};
doubleClick函数看起来很正常:
$scope.doubleClick = function () {
$timeout(function () {
//do something with your double click here
});
};
希望这有助于某人...
答案 3 :(得分:2)
我试图找到一种处理双击并同时点击的方法。我使用这里的概念来取消原始点击。如果在延迟之前发生第二次单击,则执行双击操作。如果没有第二次点击,一旦延迟结束,默认的ngClick操作就会运行,并且会在元素上触发原始事件(并允许它像最初那样冒泡)。
实施例
<div ng-click="singleClick()"><span double-click="doubleClick()">double click me</span></div>
代码
.directive('doubleClick', function($timeout, _) {
var CLICK_DELAY = 300
var $ = angular.element
return {
priority: 1, // run before event directives
restrict: 'A',
link: function(scope, element, attrs) {
var clickCount = 0
var clickTimeout
function doubleClick(e) {
e.preventDefault()
e.stopImmediatePropagation()
$timeout.cancel(clickTimeout)
clickCount = 0
scope.$apply(function() { scope.$eval(attrs.doubleClick) })
}
function singleClick(clonedEvent) {
clickCount = 0
if (attrs.ngClick) scope.$apply(function() { scope.$eval(attrs.ngClick) })
if (clonedEvent) element.trigger(clonedEvent)
}
function delaySingleClick(e) {
var clonedEvent = $.Event('click', e)
clonedEvent._delayedSingleClick = true
e.preventDefault()
e.stopImmediatePropagation()
clickTimeout = $timeout(singleClick.bind(null, clonedEvent), CLICK_DELAY)
}
element.bind('click', function(e) {
if (e._delayedSingleClick) return
if (clickCount++) doubleClick(e)
else delaySingleClick(e)
})
}
}
})
答案 4 :(得分:1)
在这里加入答案:
directive
,作为@Rob(在此主题中被接受为最佳答案的那个)ngClick
内置指令来解决@Rob回答问题
此处 Plunker 具有该想法的本质(与此答案中的代码段相同;请参阅下文)。
除了注意:理想情况下,如果没有为元素定义ng-dblclick
,则不应该阻止单击(此处为 Plunker fork 实施这个想法)
(function(angular) {
'use strict';
var myApp = angular.module('myApp', []);
myApp.controller('myCtrl', ['$scope', function($scope) {
$scope.click = false;
$scope.singleClick = function() {
$scope.click = 'single';
};
$scope.doubleClick = function() {
$scope.click = 'double';
};
}]);
// remove the buildin ng-Click, to solve issue with https://stackoverflow.com/a/20445344/4352306
myApp.config(function($provide) { // Source: https://stackoverflow.com/a/23209542/4352306
$provide.decorator('ngClickDirective', ['$delegate', function ($delegate) {
//$delegate is array of all ng-click directive, in this case
// first one is angular buildin ng-click, so we remove it.
$delegate.shift();
return $delegate;
}]);
});
// add custom single click directive: make ngClick to only trigger if not double click
myApp.directive('ngClick', ['$parse', '$timeout', dirSingleClickExclusive]);
function dirSingleClickExclusive($parse, $timeout) {
return {
restrict: 'A',
replace : false,
priority: 99, // after all build-in directive are compiled
link: link
}
function link ($scope, element, attrs) {
const delay = 400;
var clicked = false, cancelClick = false;
var user_function = $parse(attrs['ngClick']); //(scope);
element.on('click', function (e) {
// Adapted from: https://stackoverflow.com/a/29073481/4352306
if (clicked) cancelClick = true; // it is not a single click
clicked = true;
if (!cancelClick) { // prevent a second timeout
$timeout(function () { // for time window between clicks (delay)
if (cancelClick) {
clicked = false; cancelClick = false;
return;
}
$scope.$apply(function () {
user_function($scope, {$event : e});
});
// reset click status
clicked = false; cancelClick = false;
}, delay);
}
});
}
}
})(window.angular);
&#13;
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - custom single click</title>
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="myCtrl">
<button ng-click="singleClick()" ng-dblclick="doubleClick()">Click me!</button>
<p ng-if="click">This was a {{click}} click.</p>
</div>
</body>
</html>
&#13;
答案 5 :(得分:0)
如果singleClick
上的doubleClick
调用没有任何错误
<div
onclick="var scope = angular.element(this).scope(); scope.singleClick();"
ng-click="null"
ng-dblclick="doubleClick()"
></div>