From 0f9410fb3d2524dbbf3c8be22923f1fa994e9e9c Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Mon, 10 Jul 2017 13:53:42 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=84=20refactor=20infinite=20scroll=20(?= =?UTF-8?q?#325)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- assets/js/infinitescroll.js | 73 +++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 12 deletions(-) diff --git a/assets/js/infinitescroll.js b/assets/js/infinitescroll.js index 6da63cf..c5b21f6 100644 --- a/assets/js/infinitescroll.js +++ b/assets/js/infinitescroll.js @@ -1,29 +1,78 @@ // Code snippet inspired by https://github.com/douglasrodrigues5/ghost-blog-infinite-scroll $(function ($) { - var currentPage = 1, - pathname = window.location.pathname, - $window = $(window), - $document = $(document), - $result = $('.post-feed'); + var currentPage = 1; + var pathname = window.location.pathname; + var $document = $(document); + var $result = $('.post-feed'); + var buffer = 100; - function handleScroll () { - // return if not scroll to the bottom - if ($window.scrollTop() + $window.height() !== $document.height()) { + var ticking = false; + var isLoading = false; + + 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; } - if (currentPage >= maxPages) { - return $window.off('scroll', handleScroll); + // return if not scroll to the bottom + if (lastScrollY + lastWindowHeight <= lastDocumentHeight - buffer) { + ticking = false; + return; } + isLoading = true; + // next page currentPage++; // 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)); + + }).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(); });