forked from cybrespace/pinafore
start on infinite scrolling
This commit is contained in:
parent
5e3e56d454
commit
e670b57381
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue