more progress on infinite scroll
This commit is contained in:
parent
e670b57381
commit
eacf28317e
|
@ -1,16 +1,55 @@
|
||||||
|
<:Window bind:innerHeight='innerHeight'/>
|
||||||
<Nav page={{page}} />
|
<Nav page={{page}} />
|
||||||
|
|
||||||
<div class="container">
|
<div class="container" on:scroll="onScroll(event)" ref:node>
|
||||||
<main>
|
<main>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
import Nav from './Nav.html';
|
import Nav from './Nav.html';
|
||||||
|
import { virtualListStore } from '../_utils/virtualListStore'
|
||||||
|
|
||||||
|
import throttle from 'lodash/throttle'
|
||||||
|
const THROTTLE_DELAY = 500
|
||||||
|
|
||||||
export default {
|
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: {
|
components: {
|
||||||
Nav
|
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>
|
</script>
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
let i = -1
|
let i = -1
|
||||||
|
|
||||||
const createData = () => fixture.slice(0, 5).map(_ => ({
|
const createData = () => fixture.slice(0, 20).map(_ => ({
|
||||||
key: `${++i}`,
|
key: `${++i}`,
|
||||||
props: _
|
props: _
|
||||||
}))
|
}))
|
||||||
|
@ -37,7 +37,10 @@
|
||||||
splice: splice,
|
splice: splice,
|
||||||
addMoreItems() {
|
addMoreItems() {
|
||||||
console.log('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())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<:Window bind:innerHeight='innerHeight'/>
|
<div class="virtual-list">
|
||||||
<div class="virtual-list" style="height: {{$height}}px;">
|
|
||||||
<!-- <div class="virtual-list-viewport" ref:viewport></div> -->
|
<!-- <div class="virtual-list-viewport" ref:viewport></div> -->
|
||||||
{{#each $visibleItems as item @key}}
|
{{#each $visibleItems as item @key}}
|
||||||
<VirtualListItem :component
|
<VirtualListItem :component
|
||||||
|
@ -17,46 +16,24 @@
|
||||||
<script>
|
<script>
|
||||||
import VirtualListItem from './VirtualListItem'
|
import VirtualListItem from './VirtualListItem'
|
||||||
import { virtualListStore } from '../_utils/virtualListStore'
|
import { virtualListStore } from '../_utils/virtualListStore'
|
||||||
import throttle from 'lodash/throttle'
|
|
||||||
|
|
||||||
const THROTTLE_TIME = 500
|
|
||||||
const DISTANCE_FROM_BOTTOM_TO_FIRE = 400
|
const DISTANCE_FROM_BOTTOM_TO_FIRE = 400
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
oncreate () {
|
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.observe('items', (items) => {
|
||||||
this.store.set({
|
this.store.set({
|
||||||
'items': items
|
items: items
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
this.store.observe('distanceFromBottom', distanceFromBottom => {
|
|
||||||
console.log('distanceFromBottom', distanceFromBottom)
|
this.observe('distanceFromBottom', (distanceFromBottom) => {
|
||||||
if (distanceFromBottom >= 0 &&
|
//console.log('distanceFromBottom', distanceFromBottom)
|
||||||
|
if (distanceFromBottom > 0 && // hack: the first it's reported, it's always 0
|
||||||
distanceFromBottom <= DISTANCE_FROM_BOTTOM_TO_FIRE) {
|
distanceFromBottom <= DISTANCE_FROM_BOTTOM_TO_FIRE) {
|
||||||
this.fire('scrollToBottom')
|
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: () => ({
|
data: () => ({
|
||||||
component: null
|
component: null
|
||||||
|
@ -64,6 +41,11 @@
|
||||||
store: () => virtualListStore,
|
store: () => virtualListStore,
|
||||||
components: {
|
components: {
|
||||||
VirtualListItem
|
VirtualListItem
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
distanceFromBottom: ($scrollHeight, $scrollTop, $offsetHeight) => {
|
||||||
|
return $scrollHeight - $scrollTop - $offsetHeight
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
|
@ -35,7 +35,8 @@
|
||||||
oncreate() {
|
oncreate() {
|
||||||
let key = this.get('key')
|
let key = this.get('key')
|
||||||
onIntersectionCallbacks[key] = entry => {
|
onIntersectionCallbacks[key] = entry => {
|
||||||
updateItemHeights[key] = entry.boundingClientRect.height
|
let rect = entry.boundingClientRect
|
||||||
|
updateItemHeights[key] = rect.height
|
||||||
promise.then(() => {
|
promise.then(() => {
|
||||||
// update all item heights in one microtask batch for better perf
|
// update all item heights in one microtask batch for better perf
|
||||||
let updatedKeys = Object.keys(updateItemHeights)
|
let updatedKeys = Object.keys(updateItemHeights)
|
||||||
|
|
|
@ -27,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 + offsetHeight + renderBuffer)) {
|
if (currentOffset > (scrollTop + height + renderBuffer)) {
|
||||||
break // above the area we want to render
|
break // above the area we want to render
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,24 +35,12 @@ 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
|
||||||
|
|
Loading…
Reference in a new issue