Enlace de clase al evento de desplazamiento de ventana

Cuando un usuario se desplaza por la ventana de su navegador debajo de cierto punto, estoy alternando la clase del div #page.

Lo que he hecho hasta ahora funciona bien:

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

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

(cuando se desplazan por su ventana debajo del encabezado, 100px, la clase se alterna)

Aunque, corrígeme si me equivoco, creo que esta no es la forma correcta de hacer esto con Angular.

En cambio, supuse que el mejor método para hacer esto sería usar ng-class y almacenar un valor booleano en el scope. Algo como esto:

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

Aunque esto no es dynamic, si cambio el valor de scope.boolChangeClass en la callback por desplazamiento, entonces la clase ng no se está actualizando.

Entonces mi pregunta es: ¿cuál es la mejor manera de alternar la clase de #page, usando AngularJS, cuando el usuario se desplaza por debajo de cierto punto?

¿Por qué todos sugieren operaciones de gran scope? No veo por qué esta no es una solución “angular”:

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

Entonces puedes usarlo así:

  

o

 

Gracias a Flek por responder mi pregunta en su comentario:

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

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

Esta es mi solución, no es tan complicado y te permite usarlo para varias marcas a través de una simple directiva ng-class. Al igual que puede elegir la clase y los scrollPos para cada caso.

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

Su index.html:

    

fix me when scroll is equals to 100

fix me when scroll is equals to 150

trabajando JSFiddle aquí

EDITAR:

Como $apply() llama a $rootScope.$digest() puede usar $scope.$digest() lugar de $scope.$apply() para un mejor rendimiento según el contexto.
Resumen largo: $apply() siempre funcionará, pero forzará $digest en todos los ámbitos que puedan causar problemas de rendimiento.

Tal vez esto puede ayudar 🙂

Controlador

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

Html

 
//scrollable content

O

 //scrollable content 

Directiva

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

¿Qué hay del rendimiento?

  1. Siempre rebote los eventos para reducir los cálculos
  2. Use scope.applyAsync para reducir el recuento total de ciclos de digestión
 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. Si no necesita desencadenar vigilantes / digeridos en absoluto, utilice 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(); } }; }); 

Y puede usarlo como

Las directivas no están “dentro del mundo angular” como dicen. Entonces debes usar aplicar para volver a entrar cuando cambias cosas