38

要素に ng-dblclick ディレクティブが設定されていても、AngularJS は常に ng-click イベントのみを発生させるため、AngularJS を使用したシングルクリックとダブルクリックの両方のイベント処理を探していました。

解決策を求める人のための実用的なコードを次に示します。

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

あなたは自分で書くことができます。angularがクリックをどのように処理するかを見て、ここで見つけたコードでそれを変更しました: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.$evalAsync、 、scope.$apply、およびscope.$applyAsync.

$applys は s を離れる別のダイジェスト ループを開始すると思います$eval。現在の$evalコンテキストでインクルードするコードをすぐに実行し、ダイジェスト ループの最後に実行する関数をキューに入れます。基本的に、は のよりクリーンなバージョンですが、大きな違いが 1 つあります。最初のバージョンにはコンテキストがあり、スコープに存在します。$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

これに出くわし、代替手段を捨てようと思いました。2つのキーポイントを除けば、元のポスターとあまり変わらない.

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

ダブルクリックとクリックを同時に処理する方法を見つけようとしているときに遭遇しました。ここでの概念を使用して、元のクリックをキャンセルしました。遅延の前に 2 回目のクリックが発生すると、ダブルクリック アクションが実行されます。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 に答える
0

を呼び出しsingleClickdoubleClickも間違いがなければ、それも機能します

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