programing

이벤트를 제외한 모든 위치 클릭

fastcode 2023. 3. 11. 09:35
반응형

이벤트를 제외한 모든 위치 클릭

'이 요소를 제외한 모든 곳을 클릭' 이벤트를 어떻게 구현할지 궁금했습니다.

파일 탐색기의 파일 목록과 비교할 수 있는 것이 있습니다.특정 요소를 선택할 수 있지만 요소 컨트롤러 외부를 클릭하면 모든 항목을 선택 취소해야 합니다.

여기에 이미지 설명 입력

보다 선명하게 하기 위해 스크린샷 추가.따라서 언어 요소를 제외한 아무 곳이나 클릭하면 이벤트가 발생합니다.

갱신하다

분명히 말씀드리면, 저는 jQuery에서 어떻게 이것을 할 수 있는지 묻는 것이 아닙니다.

편집: 이 오래된 답변에는 몇 가지 문제가 있었습니다.

*또한 커뮤니티 Wiki에 오류가 발생하여 마킹(점수 없음)

  1. N은 N개의 디렉티브 사용을 요구합니다.이는 동일한 범위 내에서 일치하는 식과 함께 사용하는 경우에는 바람직하지 않을 수 있습니다.

  2. 이벤트 핸들러를 분해하는 것은 아무것도 없었습니다!!!나쁜 놈! 나쁜 놈!

그래서 이 답변을 업데이트 하고 있습니다.누구에게도 큰 문제가 되지 않았길 바랍니다.

갱신된 답변

이러한 문제를 해결한 새로운 플랜커가 있습니다.개별 애플리케이션 개발자가 직면하게 될 다른 문제들이 있을 수 있습니다.이것은 이 문제를 처리하는 방법의 예에 불과합니다.

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

원래 답변(이벤트 핸들러 해체 수정 포함)

당신이 찾은 하나의 답에 근접해있었지만, 나는 당신에게 무엇이 부족했는지 보여줄 수 있도록 플랭크 하나를 조립했다.

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 요소가 버블링을 방지한다는 것입니다(따라서 디렉티브를 2개의 요소로 설정하고 어느 한쪽을 클릭하면 양쪽의 콜백이 차단됩니다).

편집 - 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.callback(event)와 함께scope.$apply()

이 디렉티브가 필요한 요소가 많이 있는 경우 퍼포먼스를 최적화한 다른 솔루션이 있습니다.(이 디렉티브가 있는 행이 100개 이상인 리스트의 예)

여기에는 항상 $document 리스너가 1개만 포함됩니다.

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 솔루션의 문제는 모든 디렉티브가 $document.on('click', function(...)); 이벤트에 청취자를 추가함으로써 성능 문제가 발생한다는 것입니다.

승인된 답변에 대한 문제는 Max Bates가 이미 언급했습니다.

블로그 투고에서 anwser를 찾았습니다.

지시:

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의 솔루션을 기반으로 하지만 표준 각도 이벤트 방향 측면에서 보다 자연스러운 변종입니다.

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>

Passing click 이벤트

<div click-out="myFunction($event)"></div>

가장 간단한 방법은 요소의 범위를 확인하는 것입니다.$id 및 clickScope를 클릭합니다.$id(클릭 이벤트타깃 범위).$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);
    });
}

이 솔루션의 이점:

  1. 됩니다.$(document)기타 이벤트 발생은 다음 항목에 따라 달라집니다.$emit을 사용하다
  2. 모두 할 수 .click-elsewhere="show=false" , , , , 입니다.click-elsewhere="fn()"(덕분에).

코드:

// 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에서의 사용:

  1. click-elsewhere="fn()"
  2. click-elsewhere="show=false"

문맥에 맞지 않을 수도 있지만 선택한 모든 항목을 분류할 수 있습니다(예를 들어 "선택"을 사용). 사용자가 "여기를 클릭하지 않음" 요소를 클릭하면 현재 분류된 모든 항목의 분류를 해제하고 특정 요소를 분류할 수 있습니다.

언급URL : https://stackoverflow.com/questions/12931369/click-everywhere-but-here-event

반응형