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