💄 refactor infinite scroll (#325)

closes #321, closes #323
- use `requestAnimationFrame` and related techniques to minimise scroll processing
- add an `isLoading` guard to ensure we don't try to process anything until the next page has been loaded+inserted
- check for a 404 as an indication we've loaded as many pages as possible at which point the scroll behaviour is removed
- sanitize `window.location.pathname` to remove hash params and any double-slashes that may result
- add a 100px buffer from the bottom of the screen so that it's not necessary to exactly hit the bottom before infinite loading is triggered
This commit is contained in:
Kevin Ansfield 2017-07-10 13:53:42 +01:00 committed by Aileen Nowak
parent d3a9af0666
commit 0f9410fb3d

View file

@ -1,29 +1,78 @@
// Code snippet inspired by https://github.com/douglasrodrigues5/ghost-blog-infinite-scroll // Code snippet inspired by https://github.com/douglasrodrigues5/ghost-blog-infinite-scroll
$(function ($) { $(function ($) {
var currentPage = 1, var currentPage = 1;
pathname = window.location.pathname, var pathname = window.location.pathname;
$window = $(window), var $document = $(document);
$document = $(document), var $result = $('.post-feed');
$result = $('.post-feed'); var buffer = 100;
function handleScroll () { var ticking = false;
// return if not scroll to the bottom var isLoading = false;
if ($window.scrollTop() + $window.height() !== $document.height()) {
var lastScrollY = window.scrollY;
var lastWindowHeight = window.innerHeight;
var lastDocumentHeight = $document.height();
// remove hash params from pathname
pathname = pathname.replace(/#(.*)$/g, '').replace('/\//g', '/');
function onScroll() {
lastScrollY = window.scrollY;
requestTick();
}
function onResize() {
lastWindowHeight = window.innerHeight;
lastDocumentHeight = $document.height();
requestTick();
}
function requestTick() {
if (!ticking) {
requestAnimationFrame(infiniteScroll)
}
ticking = true;
}
function infiniteScroll () {
// return if already loading
if (isLoading) {
return; return;
} }
if (currentPage >= maxPages) { // return if not scroll to the bottom
return $window.off('scroll', handleScroll); if (lastScrollY + lastWindowHeight <= lastDocumentHeight - buffer) {
ticking = false;
return;
} }
isLoading = true;
// next page // next page
currentPage++; currentPage++;
// Load more // Load more
$.get((pathname + 'page/' + currentPage + '/'), function (content) { var nextPage = pathname + 'page/' + currentPage + '/';
$.get(nextPage, function (content) {
$result.append($(content).find('.post').hide().fadeIn(100)); $result.append($(content).find('.post').hide().fadeIn(100));
}).fail(function (xhr) {
// 404 indicates we've run out of pages
if (xhr.status === 404) {
window.removeEventListener('scroll', onScroll, {passive: true});
window.removeEventListener('resize', onResize);
}
}).always(function () {
lastDocumentHeight = $document.height();
isLoading = false;
ticking = false;
}); });
} }
$window.on('scroll', handleScroll).trigger('scroll'); window.addEventListener('scroll', onScroll, {passive: true});
window.addEventListener('resize', onResize);
infiniteScroll();
}); });