2015-04-29 12 views
17

Próbuję wywołać zdarzenie, gdy pasek przewijania osiągnie koniec. Znalazłem to this example. Oto mój kod. Problem polega na tym, że nie wywołuje on w ogóle funkcji loadmore(). Wartości statments konsoli to:Angularjs: Jak wywołać zdarzenie, gdy przewinięcie sięga do dolnej części paska przewijania w div?

848 
899 
in scroll 
881 
899 
in scroll 
892 
899 
in scroll 
897 
899 
in scroll 
900 
899 

Wydaje się, że nigdy nie dojdzie do tego if! Dziwne jest to, że jeśli debuguję element inspekcyjny, wyzwala to zdarzenie. ..... mój dyrektywy:

directive('scrolly', function() { 
    return { 
     restrict: 'A', 
     link: function (scope, element, attrs) { 
      var raw = element[0]; 
      console.log('loading directive'); 
      element.bind('scroll', function() { 
       console.log('in scroll'); 
       console.log(raw.scrollTop + raw.offsetHeight); 
       console.log(raw.scrollHeight); 
       if (raw.scrollTop + raw.offsetHeight == raw.scrollHeight) { //at the bottom 
        scope.$apply(attrs.scrolly); 
       } 
      }) 
     } 
    } 

Odpowiedz

19

Zamiast sprawdzania równości, należy sprawdzić, czy lewa strona jest większa niż po prawej stronie w if ponieważ to miejsce w przypadku przewijania do być na dole.

raw.scrollTop + raw.offsetHeight > raw.scrollHeight 

Oto działa jsfiddle.

+0

teraz – Sara

+2

Musi to być '> =', ponieważ jeśli zastąpisz 'overflow: scroll;' z 'overflow: scroll-y;' (tj. pozbyć się nieużywanego dolnego paska przewijania), wtedy 'raw.scrollTop + raw.offsetHeight' nigdy nie będzie więcej niż' raw.scrollHeight' – Stalinko

+0

Stalinko, masz absolutną rację! – Julsy

4

Szukałem urywek mi pomóc to zrobić, ale nie mógł znaleźć coś wartościowego więc wymyśliłem to dość łatwy w użyciu dyrektywy to zrobić

'use strict'; 
// Tested with Angular 1.3, 1.4.8 
angular.module('scrollToEnd', []) 
    /** 
    * @ngdoc directive 
    * @name scrollToEnd:scrollToEnd 
    * @scope 
    * @restrict A 
    * 
    * @description 
    * Supply a handler to be called when this element is scrolled all the way to any extreme. 
    * The callback must have the following signature: 
    * void function (direction:'top'|'bottom'|'left'|'right') 
    * If the `bindToWindow` attribute is truthy, the callback will be issued for the window 
    * instead of the element that the directive is on. 
    * 
    * Example usage: 
    * `<div scroll-to-end="scrollToEndWindow" bind-to-window="true">` 
    * This will call the controller's `scrollToEndWindow` function whenever the window reaches 
    * the edges when scrolling. If the div itself is a scrollable element for which the 
    * handler should be called instead, remove the bind-to-window attribute entirely. 
    * 
    * @param {function} emScrollToEnd Callback to be invoked 
    * @param {boolean}  bindToWindow  Bind to the window instead of the element 
    * 
    */ 
    .directive('scrollToEnd', function ($window) { 
    // Get the specified element's computed style (height, padding, etc.) in integer form 
    function getStyleInt(elem, prop) { 
     try { 
     return parseInt(window.getComputedStyle(elem, null).getPropertyValue(prop), 10); 
     } catch (e) { 
     return parseInt(elem.currentStyle[prop], 10); 
     } 
    } 

    // Get the 'innerHeight' equivalent for a non-window element, including padding 
    function getElementDimension(elem, prop) { 
     switch (prop) { 
     case 'width': 
      return getStyleInt(elem, 'width') + 
      getStyleInt(elem, 'padding-left') + 
      getStyleInt(elem, 'padding-right'); 
     case 'height': 
      return getStyleInt(elem, 'height') + 
      getStyleInt(elem, 'padding-top') + 
      getStyleInt(elem, 'padding-bottom'); 
     /*default: 
      return null;*/ 
     } 
    } 
    return { 
     restrict: 'A', 
     scope: { 
     callback: '=scrollToEnd' 
     }, 
     link: function (scope, elem, attr) { 
     var callback = scope.callback || function() {}; 
     var boundToWindow = attr.bindToWindow; 
     var body = document.body; 
     var html = document.documentElement; 
     var boundElement = boundToWindow ? angular.element($window) : elem; 
     var oldScrollX = 0; 
     var oldScrollY = 0; 
     var handleScroll = function() { 
      // Dimensions of the content, including everything scrollable 
      var contentWidth; 
      var contentHeight; 
      // The dimensions of the container with the scrolling, only the visible part 
      var viewportWidth; 
      var viewportHeight; 
      // The offset of how much the user has scrolled 
      var scrollX; 
      var scrollY; 

      if (boundToWindow) { 
      // Window binding case - Populate Dimensions 
      contentWidth = Math.max(
       body.scrollWidth, 
       body.offsetWidth, 
       html.clientWidth, 
       html.scrollWidth, 
       html.offsetWidth 
      ); 
      contentHeight = Math.max(
       body.scrollHeight, 
       body.offsetHeight, 
       html.clientHeight, 
       html.scrollHeight, 
       html.offsetHeight 
      ); 
      viewportWidth = window.innerWidth; 
      viewportHeight = window.innerHeight; 
      scrollX = (window.pageXOffset || html.scrollLeft) - (html.clientLeft || 0); 
      scrollY = (window.pageYOffset || html.scrollTop) - (html.clientTop || 0); 
      } else { 
      // DOM element case - Populate Dimensions 
      var domElement = boundElement[0]; 
      contentWidth = domElement.scrollWidth; 
      contentHeight = domElement.scrollHeight; 
      viewportWidth = getElementDimension(domElement, 'width'); 
      viewportHeight = getElementDimension(domElement, 'height'); 
      scrollX = domElement.scrollLeft; 
      scrollY = domElement.scrollTop; 
      } 

      var scrollWasInXDirection = oldScrollX !== scrollX; 
      var scrollWasInYDirection = oldScrollY !== scrollY; 
      oldScrollX = scrollX; 
      oldScrollY = scrollY; 

      if (scrollWasInYDirection && scrollY === 0) { 
      callback('top'); 
      } else if (scrollWasInYDirection && scrollY === contentHeight - viewportHeight) { 
      callback('bottom'); 
      } else if (scrollWasInXDirection && scrollX === 0) { 
      callback('left'); 
      } else if (scrollWasInXDirection && scrollX === contentWidth - viewportWidth) { 
      callback('right'); 
      } 
     }; 
     boundElement.bind('scroll', handleScroll); 
     // Unbind the event when scope is destroyed 
     scope.$on('$destroy', function() { 
      boundElement.unbind('scroll', handleScroll); 
     }); 
     } 
    }; 
    }); 

https://gist.github.com/podrezo/f80f35d6d0655f4d550cac4747c110ff

Oto jsfiddle go wypróbować:

https://jsfiddle.net/va4x5r26/2/

Works with Kątowymi 1.3 i 1.4.8 i testowano na IE10 i Chrome 5 5.

+0

Przekształcenie 'handleScroll' w funkcję wyrecytowaną naprawdę poprawiłoby to. Mimo to świetna robota! –

+0

Dzięki; to jest dobry pomysł –

7

Dałeś mi kilka dobrych wskazówek ... Herezje kompletny przykład pracy dla każdego, kto natyka się na ten post:

JS:

app.controller("controller", function ($scope) { 
    $scope.test = function() { 
     alert("hello!"); 
    } 
} 

HTML:

<div class="br-section1" on-scroll-to-bottom="test()"> 
</div> 

Dyrektywa aplikacyjna:

app.directive('onScrollToBottom', function ($document) { 
    //This function will fire an event when the container/document is scrolled to the bottom of the page 
    return { 
     restrict: 'A', 
     link: function (scope, element, attrs) { 

      var doc = angular.element($document)[0].body; 

      $document.bind("scroll", function() { 

       //console.log('in scroll'); 
       //console.log("scrollTop + offsetHeight:" + (doc.scrollTop + doc.offsetHeight)); 
       //console.log("scrollHeight: " + doc.scrollHeight); 

       if (doc.scrollTop + doc.offsetHeight >= doc.scrollHeight) { 
        //run the event that was passed through 
        scope.$apply(attrs.onScrollToBottom); 
       } 
      }); 
     } 
    }; 
}); 
+0

To nie działa dla mnie. W rzeczywistości kod OP dodany z odpowiedzią Rathisha działa jak urok dla mnie. Ale twoje rozwiązanie nie działa. – shanti