Подгрузка новых данных при скролле в AngularJS
Нужно показывать достаточно длинный (но не бесконечный) список фотографий, о котором известно, что в зависимости от разрешения фото могут показываться по одной или по две в ряд.
Делается это только на одном экране, а не во всем приложении (т.е. надо снимать обработчики событий и навешивать их снова при заходе на нужный экран).
Да, и еще — у нас нет jQuery, только AngularJS 1.0.8.
Сначала было решено делать все через сервис навешивания обработчиков событий, который снимает все обработчики при смене урла.
Но т.к. AngularJS-ное подобие не поддерживает нэймспэйсы для событий, то будут сниматься все обработчики на элементе, что неправильно.
Поэтому было решено сделать так:
app.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
app.run(['$rootScope', function($rootScope) { /** * To proxy global window events to angular's */ (function () { "use strict"; var rotateEvent = 'onorientationchange' in window ? 'orientationchange' : 'resize'; angular.element($window). bind('scroll', function () { $rootScope.$broadcast('scrolled.window'); }). bind(rotateEvent, function () { $rootScope.$broadcast('rotated.window'); }); }()); }]); |
Когда уходим на другой контроллер, $scope уничтожится, и обработчик вместе с ним.
Шаблон:
1 2 3 4 5 6 7 |
<div> <ul> <li ng-repeat="user in users"> <a ng-href="#/users/[[user.id]]"><img ng-src-preload="[[ user | avatar ]]" alt="" class="<strong>js-top100-photo</strong>" /></a> </li> </ul> </div> |
Сервисы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
.factory('Throttle', ['$rootScope', function throttle($rootScope) {/*будет показан отдельно*/}]) .factory('HelpersService', ['$rootScope', function HelpersService($rootScope) { var docEl = document.documentElement, docBody = document.body; return { /** * Window height */ getDocumentHeight: function getDocumentHeight() { return window.innerHeight || docEl.clientHeight || docBody.clientHeight || docEl.offsetHeight || docBody.offsetHeight; }, /** * Scrolled distance */ getDocumentScrollTop: function getDocumentScrollTop() { return window.pageYOffset || window.scrollY || docEl.scrollTop || docBody.scrollTop; } }; }]); |
Контроллер
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
controller('Top100ListCtrl', ['$scope', '$routeParams', 'HelpersService', 'Throttle', function Top100ListCtrl($scope, $routeParams, HelpersService, throttle) { ... function loadMore() { // ... } /** * Everything below is for infinite scroll-like behaviour. * When user scrolls close to the bottom, more data loaded from server. * Js needs to know about DOM: * the size of one picture (that's why we need selector 'js-top100-photo'); * the size of the window; * that there is only one or two pictures in a row. */ /** * Getting all photos from DOM by selectors. * Made only once. */ var photo1, photo2, photo3; function getPhotos() { if (! photo1) { var rawPhotos = document.getElementsByClassName('js-top100-photo'); photo1 = rawPhotos[0] ? angular.element(rawPhotos[0]) : null; photo2 = rawPhotos[0] ? angular.element(rawPhotos[1]) : null; photo3 = rawPhotos[0] ? angular.element(rawPhotos[2]) : null; } return {photo1: photo1, photo2: photo2, photo3: photo3}; } /** * Calculating and storing all heights. * Made on screen load and on screen rotation. */ var twoInARow, rowHeight, winHeight; function calcHeights(photos) { var rect1 = photos.photo1[0].getBoundingClientRect(), rect2 = photos.photo2[0].getBoundingClientRect(), rect3 = photos.photo3[0].getBoundingClientRect(), photoHeight = rect1.height; twoInARow = (rect1.top + photoHeight) > rect2.top; rowHeight = twoInARow ? rect3.top - rect1.top : rect2.top - rect1.top; winHeight = HelpersService.getDocumentHeight(); } /** * Invoked as a callback on scroll (throttled) and on device rotation. * @param {Boolean} isWindowChanged if device rotated (need recalc heights) */ function onScroll(isWindowChanged) { var photos = getPhotos(); if (photos.photo1 && photos.photo2) { if (isWindowChanged || ! rowHeight) { calcHeights(photos); } if (HelpersService.getDocumentScrollTop() > (($scope.users.length - (twoInARow ? 4 : 2)) * rowHeight - winHeight)) { loadMore(); } } } // throttling invoсation of callback for scrolling events var throttledOnScroll = throttle(200, $scope, function () { onScroll(); }); $scope.$on('scrolled.window', throttledOnScroll); $scope.$on('rotated.window', function () { onScroll(true); }); }]). |
Similar Posts
- None Found
LEAVE A COMMENT
Для отправки комментария вам необходимо авторизоваться.
2 Responses so far.