start on infinite scrolling

This commit is contained in:
Nolan Lawson 2018-01-16 21:43:31 -08:00
parent 5e3e56d454
commit e670b57381
3 changed files with 42 additions and 13 deletions

View file

@ -1,6 +1,7 @@
<div class="timeline"> <div class="timeline">
<VirtualList component="{{StatusListItem}}" items="{{statuses}}" /> <VirtualList component="{{StatusListItem}}"
<button type="button" on:click="addMoreItems()">Add more items</button> items="{{statuses}}"
on:scrollToBottom="addMoreItems()" />
</div> </div>
<style> <style>
.timeline { .timeline {
@ -17,7 +18,7 @@
let i = -1 let i = -1
const createData = () => fixture.slice(0, 20).map(_ => ({ const createData = () => fixture.slice(0, 5).map(_ => ({
key: `${++i}`, key: `${++i}`,
props: _ props: _
})) }))
@ -35,6 +36,7 @@
methods: { methods: {
splice: splice, splice: splice,
addMoreItems() { addMoreItems() {
console.log('addMoreItems')
this.splice('statuses', this.get('statuses').length, 0, ...createData()) this.splice('statuses', this.get('statuses').length, 0, ...createData())
} }
} }

View file

@ -20,12 +20,15 @@
import throttle from 'lodash/throttle' import throttle from 'lodash/throttle'
const THROTTLE_TIME = 500 const THROTTLE_TIME = 500
const DISTANCE_FROM_BOTTOM_TO_FIRE = 400
export default { export default {
oncreate () { oncreate () {
this.observe('innerHeight', throttle(innerHeight => { let container = document.body.querySelector('.container')
this.observe('innerHeight', throttle(() => {
// respond to window resize events
this.store.set({ this.store.set({
innerHeight: innerHeight offsetHeight: container.offsetHeight
}) })
}, THROTTLE_TIME)) }, THROTTLE_TIME))
this.observe('items', (items) => { this.observe('items', (items) => {
@ -33,14 +36,27 @@
'items': items 'items': items
}) })
}) })
document.body.querySelector('.container').addEventListener('scroll', throttle((e) => { this.store.observe('distanceFromBottom', distanceFromBottom => {
console.log('distanceFromBottom', distanceFromBottom)
if (distanceFromBottom >= 0 &&
distanceFromBottom <= DISTANCE_FROM_BOTTOM_TO_FIRE) {
this.fire('scrollToBottom')
}
})
container.addEventListener('scroll', throttle((e) => {
this.store.set({ this.store.set({
scrollTop: e.target.scrollTop scrollTop: e.target.scrollTop,
scrollHeight: e.target.scrollHeight
}, { }, {
leading: false, leading: false,
trailing: true trailing: true
}) })
}, THROTTLE_TIME)) }, THROTTLE_TIME))
this.store.set({
scrollTop: container.scrollTop,
scrollHeight: container.scrollHeight,
offsetHeight: container.offsetHeight
})
}, },
data: () => ({ data: () => ({
component: null component: null

View file

@ -6,13 +6,12 @@ class VirtualListStore extends Store {
const virtualListStore = new VirtualListStore({ const virtualListStore = new VirtualListStore({
items: [], items: [],
itemHeights: {}, itemHeights: {},
scrollTop: 0
}) })
virtualListStore.compute('visibleItems', virtualListStore.compute('visibleItems',
['items', 'scrollTop', 'height', 'itemHeights', 'innerHeight'], ['items', 'scrollTop', 'itemHeights', 'offsetHeight'],
(items, scrollTop, height, itemHeights, innerHeight) => { (items, scrollTop, itemHeights, offsetHeight) => {
let renderBuffer = 1.5 * innerHeight let renderBuffer = 1.5 * offsetHeight
let visibleItems = [] let visibleItems = []
let totalOffset = 0 let totalOffset = 0
let len = items.length let len = items.length
@ -28,7 +27,7 @@ virtualListStore.compute('visibleItems',
continue // below the area we want to render continue // below the area we want to render
} }
} else { } else {
if (currentOffset > (scrollTop + innerHeight + renderBuffer)) { if (currentOffset > (scrollTop + offsetHeight + renderBuffer)) {
break // above the area we want to render break // above the area we want to render
} }
} }
@ -36,12 +35,24 @@ virtualListStore.compute('visibleItems',
offset: currentOffset, offset: currentOffset,
props: props, props: props,
key: key, key: key,
index: i index: i,
height: height
}) })
} }
return visibleItems return visibleItems
}) })
virtualListStore.compute('distanceFromBottom',
['scrollHeight', 'scrollTop', 'offsetHeight'],
(scrollHeight, scrollTop, offsetHeight) => {
if (typeof scrollHeight === 'undefined' ||
typeof scrollTop === 'undefined' ||
typeof offsetHeight === 'undefined') {
return -1
}
return scrollHeight - scrollTop - offsetHeight
})
virtualListStore.compute('height', ['items', 'itemHeights'], (items, itemHeights) => { virtualListStore.compute('height', ['items', 'itemHeights'], (items, itemHeights) => {
let sum = 0 let sum = 0
let i = -1 let i = -1