将类切换绑定到窗口滚动事件

时间:2013-02-14 15:54:13

标签: angularjs angularjs-directive

当用户将浏览器窗口滚动到某个点以下时,我正在切换#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类?

6 个答案:

答案 0 :(得分:86)

感谢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();
        });
    };
});

答案 1 :(得分:23)

为什么你们都建议重型作业?我不明白为什么这不是一个“有角度”的解决方案:

.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>

答案 2 :(得分:16)

这是我的解决方案,它不是那么棘手,并且允许您通过简单的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 here

编辑:

  

由于$apply()实际上是在调用$rootScope.$digest()   直接使用$scope.$digest()代替$scope.$apply()   根据具体情况改善表现。
  长话短说:$apply()   将始终有效但强制$digest可能导致所有范围   性能问题。

答案 3 :(得分:2)

也许这有助于:)

控制器

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

答案 4 :(得分:0)

性能怎么样?

  1. 始终去抖动事件以减少计算
  2. 使用scope.applyAsync减少整体摘要周期数
  3. 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。如果您根本不需要触发观察者/摘要,请使用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();
            }
        };
      });
    

    您可以像<header class-scroll="header--scrolled">

    一样使用它

答案 5 :(得分:-4)

他们说,指令不是“在有角度的世界里面”。因此,在更改内容时,您必须使用apply来重新使用