Program Club

창 스크롤 이벤트에 클래스 토글 바인딩

proclub 2020. 12. 7. 21:06
반응형

창 스크롤 이벤트에 클래스 토글 바인딩


사용자가 브라우저 창을 특정 지점 아래로 스크롤하면 #page div의 클래스를 전환합니다.

지금까지 내가 한 일은 잘 작동합니다.

http://jsfiddle.net/eTTZj/29/

<div ng-app="myApp" scroll id="page">

    <header></header>
    <section></section>

</div>

app = angular.module('myApp', []);
app.directive("scroll", function ($window) {
    return function(scope, element, attrs) {
        angular.element($window).bind("scroll", function() {
             if (this.pageYOffset >= 100) {
                 element.addClass('min');
                 console.log('Scrolled below header.');
             } else {
                 element.removeClass('min');
                 console.log('Header is in view.');
             }
        });
    };
});

(헤더 아래로 창을 스크롤하면 100px, 클래스가 토글됩니다)

비록 내가 틀렸다면 나를 고쳐 주지만 이것이 Angular로 이것을하는 올바른 방법이 아니라고 생각합니다.

대신이 작업을 수행하는 가장 좋은 방법은 ng-class를 사용하고 범위에 부울 값을 저장하는 것이라고 가정했습니다. 이 같은:

<div ng-app="myApp" scroll id="page" ng-class="{min: boolChangeClass}">

    <header></header>
    <section></section>

</div>

app = angular.module('myApp', []);
app.directive("scroll", function ($window) {
    return function(scope, element, attrs) {
        angular.element($window).bind("scroll", function() {
             if (this.pageYOffset >= 100) {
                 scope.boolChangeClass = true;
                 console.log('Scrolled below header.');
             } else {
                 scope.boolChangeClass = false;
                 console.log('Header is in view.');
             }
        });
    };
});

이것은 동적이 아니지만 스크롤 콜백에서 scope.boolChangeClass의 값을 변경하면 ng-class가 업데이트되지 않습니다.

그래서 내 질문은 : 사용자가 특정 지점 아래로 스크롤 할 때 AngularJS를 사용하여 #page 클래스를 전환하는 가장 좋은 방법은 무엇입니까?


왜 모두 무거운 범위의 작업을 제안합니까? 왜 이것이 "각도"솔루션이 아닌지 모르겠습니다.

.directive('changeClassOnScroll', function ($window) {
  return {
    restrict: 'A',
    scope: {
        offset: "@",
        scrollClass: "@"
    },
    link: function(scope, element) {
        angular.element($window).bind("scroll", function() {
            if (this.pageYOffset >= parseInt(scope.offset)) {
                element.addClass(scope.scrollClass);
            } else {
                element.removeClass(scope.scrollClass);
            }
        });
    }
  };
})

따라서 다음과 같이 사용할 수 있습니다.

<navbar change-class-on-scroll offset="500" scroll-class="you-have-scrolled-down"></navbar>

또는

<div change-class-on-scroll offset="500" scroll-class="you-have-scrolled-down"></div>

그의 의견에 내 질문에 답한 Flek에게 감사드립니다.

http://jsfiddle.net/eTTZj/30/

<div ng-app="myApp" scroll id="page" ng-class="{min:boolChangeClass}">

    <header></header>
    <section></section>

</div>

app = angular.module('myApp', []);
app.directive("scroll", function ($window) {
    return function(scope, element, attrs) {
        angular.element($window).bind("scroll", function() {
             if (this.pageYOffset >= 100) {
                 scope.boolChangeClass = true;
             } else {
                 scope.boolChangeClass = false;
             }
            scope.$apply();
        });
    };
});

이것은 내 솔루션이며, 그렇게 까다 롭지 않으며 간단한 ng-class 지시문을 통해 여러 마크 업에 사용할 수 있습니다. 이와 같이 각 경우에 대한 클래스와 scrollPos를 선택할 수 있습니다.

귀하의 App.js :

angular.module('myApp',[])
    .controller('mainCtrl',function($window, $scope){
        $scope.scrollPos = 0;

        $window.onscroll = function(){
            $scope.scrollPos = document.body.scrollTop || document.documentElement.scrollTop || 0;
            $scope.$apply(); //or simply $scope.$digest();
        };
    });

귀하의 index.html :

<html ng-app="myApp">
    <head></head>
    <body>
        <section ng-controller="mainCtrl">
            <p class="red" ng-class="{fix:scrollPos >= 100}">fix me when scroll is equals to 100</p>
            <p class="blue" ng-class="{fix:scrollPos >= 150}">fix me when scroll is equals to 150</p>
        </section>
    </body>
</html>

여기 에서 JSFiddle 작업

편집하다 :

$apply()실제로 호출하는 것과 같이 컨텍스트에 따라 더 나은 성능 대신 $rootScope.$digest()직접 사용할 수 있습니다 . 간단히 말해서 : 항상 작동하지만 성능 문제를 일으킬 수있는 모든 범위를 강제합니다 .$scope.$digest()$scope.$apply()
$apply()$digest


아마도 이것이 도움이 될 수 있습니다 :)

제어 장치

$scope.scrollevent = function($e){
   // Your code
}

HTML

<div scroll scroll-event="scrollevent">//scrollable content</div>

또는

<body scroll scroll-event="scrollevent">//scrollable content</body>

지령

.directive("scroll", function ($window) {
   return {
      scope: {
         scrollEvent: '&'
      },
      link : function(scope, element, attrs) {
        $("#"+attrs.id).scroll(function($e) { scope.scrollEvent != null ?  scope.scrollEvent()($e) : null })
      }
   }
})

성능은 어떻습니까?

  1. Always debounce events to reduce calculations
  2. Use scope.applyAsync to reduce overall digest cycles count
function debounce(func, wait) {
    var timeout;
    return function () {
        var context = this, args = arguments;
        var later = function () {
            timeout = null;
            func.apply(context, args);
        };

        if (!timeout) func.apply(context, args);
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
    };
}

angular.module('app.layout')
  .directive('classScroll', function ($window) {    
    return {
        restrict: 'A',
        link: function (scope, element) {    
            function toggle() {
                angular.element(element)
                  .toggleClass('class-scroll--scrolled', 
                    window.pageYOffset > 0);
                scope.$applyAsync();
            }    
            angular.element($window)
              .on('scroll', debounce(toggle, 50));

            toggle();
        }
    };
});

3. If you don't need to trigger watchers/digests at all then use compile

.directive('classScroll', function ($window, utils) {
    return {
        restrict: 'A',
        compile: function (element, attributes) {
            function toggle() {
                angular.element(element)
                  .toggleClass(attributes.classScroll,
                    window.pageYOffset > 0);
            }

            angular.element($window)
              .on('scroll', utils.debounce(toggle, 50));
            toggle();
        }
    };
  });

And you can use it like <header class-scroll="header--scrolled">


Directives are not "inside the angular world" as they say. So you have to use apply to get back into it when changing stuff

참고URL : https://stackoverflow.com/questions/14878761/bind-class-toggle-to-window-scroll-event

반응형