implement AsyncLayout
This commit is contained in:
parent
b58033203d
commit
0f69df592a
|
@ -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
|
||||||
|
|
|
@ -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 }
|
Loading…
Reference in New Issue