more progress on infinite scroll

This commit is contained in:
Nolan Lawson 2018-01-16 23:16:15 -08:00
parent e670b57381
commit eacf28317e
5 changed files with 61 additions and 48 deletions

View file

@ -1,16 +1,55 @@
<:Window bind:innerHeight='innerHeight'/>
<Nav page={{page}} />
<div class="container">
<div class="container" on:scroll="onScroll(event)" ref:node>
<main>
<slot></slot>
</main>
</div>
<script>
import Nav from './Nav.html';
import { virtualListStore } from '../_utils/virtualListStore'
import throttle from 'lodash/throttle'
const THROTTLE_DELAY = 500
export default {
oncreate() {
this.observe('innerHeight', throttle(() => {
// respond to window resize events
this.store.set({
offsetHeight: this.refs.node.offsetHeight
})
}, THROTTLE_DELAY))
this.store.set({
scrollTop: this.refs.node.scrollTop,
scrollHeight: this.refs.node.scrollHeight,
offsetHeight: this.refs.node.offsetHeight
})
},
components: {
Nav
}
},
store: () => virtualListStore,
events: {
scroll(node, callback) {
const onScroll = throttle(callback, THROTTLE_DELAY)
node.addEventListener('scroll', onScroll);
return {
teardown() {
node.removeEventListener('scroll', onScroll);
}
};
}
},
methods: {
onScroll(event) {
this.store.set({
scrollTop: event.target.scrollTop,
scrollHeight: event.target.scrollHeight
})
}
}
};
</script>

View file

@ -18,7 +18,7 @@
let i = -1
const createData = () => fixture.slice(0, 5).map(_ => ({
const createData = () => fixture.slice(0, 20).map(_ => ({
key: `${++i}`,
props: _
}))
@ -37,7 +37,10 @@
splice: splice,
addMoreItems() {
console.log('addMoreItems')
this.splice('statuses', this.get('statuses').length, 0, ...createData())
let statuses = this.get('statuses')
if (statuses) {
this.splice('statuses', statuses.length, 0, ...createData())
}
}
}
}

View file

@ -1,5 +1,4 @@
<:Window bind:innerHeight='innerHeight'/>
<div class="virtual-list" style="height: {{$height}}px;">
<div class="virtual-list">
<!-- <div class="virtual-list-viewport" ref:viewport></div> -->
{{#each $visibleItems as item @key}}
<VirtualListItem :component
@ -17,46 +16,24 @@
<script>
import VirtualListItem from './VirtualListItem'
import { virtualListStore } from '../_utils/virtualListStore'
import throttle from 'lodash/throttle'
const THROTTLE_TIME = 500
const DISTANCE_FROM_BOTTOM_TO_FIRE = 400
export default {
oncreate () {
let container = document.body.querySelector('.container')
this.observe('innerHeight', throttle(() => {
// respond to window resize events
this.store.set({
offsetHeight: container.offsetHeight
})
}, THROTTLE_TIME))
this.observe('items', (items) => {
this.store.set({
'items': items
items: items
})
})
this.store.observe('distanceFromBottom', distanceFromBottom => {
console.log('distanceFromBottom', distanceFromBottom)
if (distanceFromBottom >= 0 &&
this.observe('distanceFromBottom', (distanceFromBottom) => {
//console.log('distanceFromBottom', distanceFromBottom)
if (distanceFromBottom > 0 && // hack: the first it's reported, it's always 0
distanceFromBottom <= DISTANCE_FROM_BOTTOM_TO_FIRE) {
this.fire('scrollToBottom')
}
})
container.addEventListener('scroll', throttle((e) => {
this.store.set({
scrollTop: e.target.scrollTop,
scrollHeight: e.target.scrollHeight
}, {
leading: false,
trailing: true
})
}, THROTTLE_TIME))
this.store.set({
scrollTop: container.scrollTop,
scrollHeight: container.scrollHeight,
offsetHeight: container.offsetHeight
})
},
data: () => ({
component: null
@ -64,6 +41,11 @@
store: () => virtualListStore,
components: {
VirtualListItem
},
computed: {
distanceFromBottom: ($scrollHeight, $scrollTop, $offsetHeight) => {
return $scrollHeight - $scrollTop - $offsetHeight
}
}
}
</script>

View file

@ -35,7 +35,8 @@
oncreate() {
let key = this.get('key')
onIntersectionCallbacks[key] = entry => {
updateItemHeights[key] = entry.boundingClientRect.height
let rect = entry.boundingClientRect
updateItemHeights[key] = rect.height
promise.then(() => {
// update all item heights in one microtask batch for better perf
let updatedKeys = Object.keys(updateItemHeights)

View file

@ -27,7 +27,7 @@ virtualListStore.compute('visibleItems',
continue // below the area we want to render
}
} else {
if (currentOffset > (scrollTop + offsetHeight + renderBuffer)) {
if (currentOffset > (scrollTop + height + renderBuffer)) {
break // above the area we want to render
}
}
@ -35,24 +35,12 @@ virtualListStore.compute('visibleItems',
offset: currentOffset,
props: props,
key: key,
index: i,
height: height
index: i
})
}
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) => {
let sum = 0
let i = -1