implement AsyncLayout

This commit is contained in:
Nolan Lawson 2018-01-17 19:16:04 -08:00
parent b58033203d
commit 0f69df592a
2 changed files with 36 additions and 22 deletions

View File

@ -20,28 +20,20 @@
</style> </style>
<script> <script>
import { virtualListStore } from '../_utils/virtualListStore' import { virtualListStore } from '../_utils/virtualListStore'
import { AsyncLayout } from '../_utils/AsyncLayout'
import { mark, stop } from '../_utils/marks' import { mark, stop } from '../_utils/marks'
let updateItemHeights = {} let updateItemHeights = {}
let promise = Promise.resolve() let promise = Promise.resolve()
let onIntersectionCallbacks = {}
let intersectionObserver = new IntersectionObserver(entries => { const asyncLayout = new AsyncLayout(node => node.getAttribute('virtual-list-key'))
entries.forEach(entry => {
let key = entry.target.getAttribute('virtual-list-key')
onIntersectionCallbacks[key](entry)
})
})
export default { export default {
oncreate() { oncreate() {
let key = this.get('key') let key = this.get('key')
// TODO: implement AsyncLayout
// TODO: implement batchUpdate // TODO: implement batchUpdate
// TODO: fix resize on media // TODO: fix resize on media
onIntersectionCallbacks[key] = entry => { asyncLayout.observe(key, this.refs.node, (rect) => {
console.log('onIntersection', key, entry.boundingClientRect.height)
let rect = entry.boundingClientRect
updateItemHeights[key] = rect.height updateItemHeights[key] = rect.height
promise = promise.then(() => { promise = promise.then(() => {
// update all item heights in one microtask batch for better perf // update all item heights in one microtask batch for better perf
@ -61,22 +53,13 @@
updateItemHeights = {} updateItemHeights = {}
stop('batch update VirtualListItem') stop('batch update VirtualListItem')
}) })
this.set({ unobserved: true }) })
intersectionObserver.unobserve(this.refs.node)
}
intersectionObserver.observe(this.refs.node)
}, },
ondestroy() { ondestroy() {
let key = this.get('key') let key = this.get('key')
if (!this.get('unobserved')) { asyncLayout.unobserve(key, this.refs.node)
intersectionObserver.unobserve(this.refs.node)
}
delete onIntersectionCallbacks[key]
delete updateItemHeights[key] delete updateItemHeights[key]
}, },
data: () => ({
unobserved: false
}),
store: () => virtualListStore, store: () => virtualListStore,
computed: { computed: {
'shown': ($itemHeights, key) => $itemHeights[key] > 0 'shown': ($itemHeights, key) => $itemHeights[key] > 0

View File

@ -0,0 +1,31 @@
// Use intersection observer to calculate rects asynchronously
class AsyncLayout {
constructor(generateKeyFromNode) {
this._onIntersectionCallbacks = {}
this._intersectionObserver = new IntersectionObserver(entries => {
entries.forEach(entry => {
let key = generateKeyFromNode(entry.target)
this._onIntersectionCallbacks[key](entry)
})
})
}
observe(key, node, callback) {
this._onIntersectionCallbacks[key] = (entry) => {
callback(entry.boundingClientRect)
this.unobserve(key, node)
}
this._intersectionObserver.observe(node)
}
unobserve(key, node) {
if (key in this._onIntersectionCallbacks) {
return
}
this._intersectionObserver.unobserve(node)
delete this._onIntersectionCallbacks[key]
}
}
export { AsyncLayout }