Bind-class wechselt zum Fenster-Scroll-Ereignis

Wenn ein Benutzer in seinem Browserfenster unterhalb eines bestimmten Punktes scrollt, schalte ich die class des #page div um.

Was ich bisher gemacht habe funktioniert gut:

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

(wenn sie in ihrem Fenster unterhalb der Kopfzeile 100px scrollen, wird die class umgeschaltet)

Obwohl, korrigieren Sie mich, wenn ich falsch liege, ich fühle, dass dies nicht der richtige Weg ist, dies mit Angular zu tun.

Stattdessen nahm ich an, dass die beste Methode dafür wäre, indem Sie ng-class verwenden und einen booleschen Wert im Bereich speichern. Etwas wie das:

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

Obwohl dies nicht dynamisch ist, wird die ng-class nicht aktualisiert, wenn ich den Wert von scope.boolChangeClass im Scroll-Callback ändere.

Meine Frage ist also: Wie lässt sich die class von #page am besten mit AngularJS umschalten, wenn der Benutzer unterhalb eines bestimmten Punktes scrollt?

Warum schlagen Sie alle schwere Operationen vor? Ich verstehe nicht, warum das keine “eckige” Lösung ist:

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

So können Sie es wie folgt verwenden:

  

oder

 

Danke an Flek für die Beantwortung meiner Frage in seinem Kommentar:

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

Dies ist meine Lösung, es ist nicht so schwierig und erlaubt Ihnen, es für mehrere Markups durch eine einfache ng-class-Direktive zu verwenden. So können Sie die class und die ScrollPos für jeden Fall auswählen.

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

Dein Index.html:

    

fix me when scroll is equals to 100

fix me when scroll is equals to 150

JSFiddle hier zu arbeiten

EDIT:

Da $apply() tatsächlich $rootScope.$digest() , können Sie direkt $scope.$digest() anstelle von $scope.$apply() um je nach Kontext eine bessere performance zu erzielen.
Lange Rede, kurzer Sinn: $apply() wird immer funktionieren, aber den $digest in allen Bereichen erzwingen, die das Performance-Problem verursachen könnten.

Vielleicht kann das helfen 🙂

Regler

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

Html

 
//scrollable content

Oder

 //scrollable content 

Richtlinie

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

Was ist mit performance?

  1. Entprellen Sie Ereignisse immer, um die Berechnungen zu reduzieren
  2. Verwenden Sie scope.applyAsync , um die Gesamtzahl der Digest-Zyklen zu reduzieren
 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. Wenn Sie Watcher / Digests überhaupt nicht auslösen müssen, verwenden Sie 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(); } }; }); 

Und Sie können es wie

Richtlinien sind nicht “in der eckigen Welt”, wie sie sagen. Also musst du apply verwenden, um beim Ändern von Sachen wieder darauf zurückzugreifen