38

我一直在寻找 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”指令来处理仅单击代码的代码。不知道这是否可能,但我会发现它对每个人都非常有用。

随时分享您的意见!

4

6 回答 6

29

你可以自己写。我看了一下角度如何处理点击并用我在这里找到的代码对其进行了修改:Jquery bind double click and single click separate

<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
              }
          });
        }
    };
}])

这是一个例子

普朗克

于 2013-12-07T19:05:31.250 回答
26

格雷格的答案绝对最接近最干净的答案。我将在他的回答的基础上提出一个不需要编写新代码并且不需要在控制器中使用新注入的版本。

首先要质疑的是为什么使用超时来解决这类问题。本质上,它们用于使函数跳过当前事件循环的其余部分,以便执行干净。然而,在 Angular 中,您实际上对摘要循环的工作方式感兴趣。它与您的经典事件处理程序几乎相同,除了一些使其非常适合 UX 的细微差别。您手头上可以处理函数执行顺序的一些工具包括scope.$evalscope.$evalAsyncscope.$applyscope.$applyAsync.

我相信$applys 会启动另一个摘要循环,它会留下$evals。$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>

这是一个使用 Angular 1.6.4 具有预期功能的 jsfiddle

于 2015-07-11T02:06:22.703 回答
14

遇到这个,并认为我会抛出一个替代方案。除了两个关键点之外,它与原始海报并没有太大区别。

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

    });
};

希望这可以帮助某人...

于 2015-03-16T09:35:31.963 回答
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)
      })

    }
  }

})
于 2014-08-05T03:00:10.810 回答
1

在这里加入答案:

这里是具有想法本质的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);
<!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>

于 2018-01-20T02:18:42.060 回答
0

如果调用没有任何错误singleClick,它也可以工作doubleClick

<div 
    onclick="var scope = angular.element(this).scope(); scope.singleClick();"
    ng-click="null" 
    ng-dblclick="doubleClick()"
></div>
于 2017-03-27T09:07:12.007 回答