The current state of infinite-scroll.js from the default Casper theme is buggy . I’m going to improve the script and make it work.
Found out it’s my own fault for editing index.hbs
file. I didn’t expect you need to add extra argument page
to load correct offset from a list. Get Posts exclude tags ;(() => {
const nextElement = document.querySelector('link[rel=next]'), // next link element
feedElement = document.querySelector('.post-feed') // post feed element
if (!nextElement || !feedElement) return
const state = {
activeZoneHeight: 300,
ticking: false,
lastScrollY: window.scrollY,
lastWindowHeight: window.innerHeight,
lastDocumentHeight: document.documentElement.scrollHeight,
href: nextElement.href
}
const app = {
loading: false,
onPageLoad(doc) {
const nextElement = doc.querySelector('link[rel=next]')
state.href = nextElement && nextElement.href
!state.href && EventListeners.onDestroy()
const postElements = doc.querySelectorAll('.post-card')
Array.from(postElements).forEach(item => {
console.log(`# ${item.querySelector('.post-card-title').innerHTML}`)
// document.importNode is important, without it the item's owner
// document will be different which can break resizing of
// `object-fit: cover` images in Safari
// feedElement.appendChild(body.importNode(item, true))
feedElement.appendChild(item)
})
},
onUpdate() {
const {
lastScrollY,
lastWindowHeight,
lastDocumentHeight,
activeZoneHeight,
href
} = state,
{ loading } = this
if (loading || !href) return
// return if not scroll to the bottom
if (
lastScrollY + lastWindowHeight <=
lastDocumentHeight - activeZoneHeight
) {
state.ticking = false
return
}
this.loading = true
console.log('---- onUpdate: START', { href })
fetch(href)
.then(r => r.text())
.then(text => new DOMParser().parseFromString(text, 'text/html'))
.then(this.onPageLoad)
.then(() => {
console.log('---- onUpdate: END')
// sync status
this.loading = false
state.lastDocumentHeight = document.documentElement.scrollHeight
state.ticking = false
})
}
}
const requestTick = () => {
state.ticking || requestAnimationFrame(app.onUpdate.bind(app))
state.ticking = true
},
onScroll = event => {
state.lastScrollY = window.scrollY
requestTick()
},
onResize = event => {
state.lastWindowHeight = window.innerHeight
state.lastDocumentHeight = document.documentElement.scrollHeight
requestTick()
}
const factoryListener = list => {
let isCreated = false
return {
onCreate() {
if (!isCreated) {
list.forEach(element => addEventListener(...element))
isCreated = true
}
},
onDestroy() {
if (isCreated) {
list.forEach(element => removeEventListener(...element))
isCreated = false
}
}
}
}
const eventListeners = [
['scroll', onScroll, { passive: true }],
['resize', onResize]
],
EventListeners = factoryListener(eventListeners)
EventListeners.onCreate()
})()
File: infinite-scroll.js
I made little bloat for factoryListener
function. It’s an idea to have multiple listeners in a list to destroy later if you worry about memory management or element manipulation. Some best practises are when you create an addEventListner
you must have removeEventListener
too clean it up.