使用AngularJS处理相同元素的ng-click和ng-dblclick

ste*_*alz 38 javascript angularjs angularjs-directive angularjs-ng-click

我正在寻找使用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.
         * ...
         */

    };

}
Run Code Online (Sandbox Code Playgroud)

HTML:

<div ng-controller="MyController">
    <a href="#" ng-click="singleClickAction()">CLICK</a>
</div>
Run Code Online (Sandbox Code Playgroud)

所以我的问题是(因为我是一个AngularJS新手):有人可以更有经验地写一些很好的指令来处理这两个事件吗?

在我看来,完美的方法是改变ng-click,ng-dblclick的行为,并添加一些"ng-sglclick"指令来处理单击式代码.不知道它是否可能,但我发现它对每个人都非常有用.

随意分享您的意见!

Rob*_*Rob 28

你可以写自己的.我看了一下如何处理角点击并使用我在这里找到的代码修改它:Jquery绑定双击并单击单击

<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
              }
          });
        }
    };
}])
Run Code Online (Sandbox Code Playgroud)

这是一个例子

Plunker

  • 这是一个非常好的解决方案,但它确实会在将点击视为单击处理之前造成延迟.如果您观看例如Windows资源管理器的UI,您将看到无论是单击还是双击,都会发生单击操作.他们的诀窍是确保单击导致的任何事情都不会中断双击的意图.换句话说,如果您只是删除超时并适当地处理事件,您可能会获得更好的用户体验. (6认同)
  • 你应该使用angular和`$ timeout.clear(timer)`提供的`$ timeout`,这样你就不需要`$ apply`了,你可以在单元测试中刷新它. (3认同)

sti*_*tes 25

格雷格的答案绝对是最贴心的答案.我将以他的答案为基础,提出一个不需要编写新代码的版本,并且不需要在控制器中使用新的注入.

首先要问的是为什么超时会被用来解决这些问题.本质上,它们用于使函数跳过当前事件循环的其余部分,以便执行是干净的.但是,在角度中,您实际上对摘要循环的工作原理感兴趣.它与您的经典事件处理程序几乎相同,除了一些微小的差异,这使得它非常适合用户体验.你手头上有更动功能的执行顺序的一些工具包括scope.$eval,scope.$evalAsync,scope.$apply,和scope.$applyAsync.

我相信$applys会启动另一个消化循环,离开$evals.$eval将使用当前上下文立即运行您包含的任何代码$scope,$evalAsync并将您的函数排入队列以在摘要循环结束时运行.从本质上讲,$evalAsync是一个更清晰的版本,$timeout有一个很大的区别 - 第一个有上下文,存在于范围内!

这意味着你可以,实际上,处理ng-clickng-dblclick在相同的元素.但请注意,这仍然会在双击功能之前触发单击功能.这应该足够了:

<div ng-controller="MyController">
    <a href="#"
       ng-click="$evalAsync(singleClickAction())"
       ng-dblclick="doubleClickAction()">
       CLICK
    </a>
</div>
Run Code Online (Sandbox Code Playgroud)

这是使用Angular 1.6.4的预期功能的jsfiddle.


Gre*_*ter 13

遇到这个并认为我会抛弃另一种选择.除了两个关键点之外,它与原始海报没有什么不同.

1)没有嵌套的函数声明.

2)我使用$ timeout.我经常使用$ timeout,即使没有延迟......特别是如果我开始承诺做其他工作.当摘要周期到来时,$ timeout将触发,这将确保应用范围内的任何数据更改.

特定

<img src="myImage.jpg" ng-click="singleClick()" ng-dblclick="doubleClick()">
Run Code Online (Sandbox Code Playgroud)

在您的控制器中,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);
};
Run Code Online (Sandbox Code Playgroud)

而doubleClick函数看起来很正常:

$scope.doubleClick = function () {

    $timeout(function () {

        //do something with your double click here

    });
};
Run Code Online (Sandbox Code Playgroud)

希望这有助于某人......