2018-01-17 04:34:09 +00:00
|
|
|
<div class="virtual-list-item {{shown ? 'shown' : ''}}"
|
|
|
|
virtual-list-key="{{key}}"
|
2018-01-15 18:54:02 +00:00
|
|
|
ref:node
|
2018-01-16 00:12:07 +00:00
|
|
|
style="transform: translate3d(0, {{offset}}px, 0);"
|
2018-01-15 20:23:28 +00:00
|
|
|
>
|
|
|
|
<:Component {component} virtualProps="{{props}}" />
|
2018-01-15 18:54:02 +00:00
|
|
|
</div>
|
|
|
|
<style>
|
|
|
|
.virtual-list-item {
|
|
|
|
position: absolute;
|
|
|
|
top: 0;
|
2018-01-17 04:34:09 +00:00
|
|
|
opacity: 0;
|
|
|
|
pointer-events: none;
|
2018-01-17 08:06:24 +00:00
|
|
|
/* will-change: transform; */ /* causes jank in mobile Firefox */
|
2018-01-17 04:34:09 +00:00
|
|
|
}
|
|
|
|
.shown {
|
|
|
|
opacity: 1;
|
|
|
|
pointer-events: auto;
|
2018-01-15 18:54:02 +00:00
|
|
|
}
|
|
|
|
</style>
|
|
|
|
<script>
|
2018-01-15 20:23:28 +00:00
|
|
|
import { virtualListStore } from '../_utils/virtualListStore'
|
2018-01-17 08:59:15 +00:00
|
|
|
import { mark, stop } from '../_utils/marks'
|
2018-01-15 20:23:28 +00:00
|
|
|
|
2018-01-17 02:08:37 +00:00
|
|
|
let updateItemHeights = {}
|
|
|
|
let promise = Promise.resolve()
|
2018-01-17 04:34:09 +00:00
|
|
|
let onIntersectionCallbacks = {}
|
|
|
|
|
|
|
|
let intersectionObserver = new IntersectionObserver(entries => {
|
|
|
|
entries.forEach(entry => {
|
|
|
|
let key = entry.target.getAttribute('virtual-list-key')
|
|
|
|
onIntersectionCallbacks[key](entry)
|
|
|
|
})
|
|
|
|
})
|
2018-01-17 02:08:37 +00:00
|
|
|
|
2018-01-15 18:54:02 +00:00
|
|
|
export default {
|
|
|
|
oncreate() {
|
2018-01-16 00:35:08 +00:00
|
|
|
let key = this.get('key')
|
2018-01-18 02:35:27 +00:00
|
|
|
// TODO: implement AsyncLayout
|
|
|
|
// TODO: implement batchUpdate
|
|
|
|
// TODO: fix resize on media
|
2018-01-17 04:34:09 +00:00
|
|
|
onIntersectionCallbacks[key] = entry => {
|
2018-01-18 02:35:27 +00:00
|
|
|
console.log('onIntersection', key, entry.boundingClientRect.height)
|
2018-01-17 07:16:15 +00:00
|
|
|
let rect = entry.boundingClientRect
|
|
|
|
updateItemHeights[key] = rect.height
|
2018-01-18 02:35:27 +00:00
|
|
|
promise = promise.then(() => {
|
2018-01-17 04:34:09 +00:00
|
|
|
// update all item heights in one microtask batch for better perf
|
|
|
|
let updatedKeys = Object.keys(updateItemHeights)
|
|
|
|
if (!updatedKeys.length) {
|
|
|
|
return
|
|
|
|
}
|
2018-01-17 08:59:15 +00:00
|
|
|
mark('batch update VirtualListItem')
|
2018-01-17 04:34:09 +00:00
|
|
|
// batch all updates to itemHeights for better perf
|
|
|
|
let itemHeights = this.store.get('itemHeights')
|
|
|
|
for (key of updatedKeys) {
|
|
|
|
itemHeights[key] = updateItemHeights[key]
|
|
|
|
}
|
|
|
|
this.store.set({
|
|
|
|
itemHeights: itemHeights
|
|
|
|
})
|
|
|
|
updateItemHeights = {}
|
2018-01-17 08:59:15 +00:00
|
|
|
stop('batch update VirtualListItem')
|
2018-01-17 02:08:37 +00:00
|
|
|
})
|
2018-01-18 02:35:27 +00:00
|
|
|
this.set({ unobserved: true })
|
|
|
|
intersectionObserver.unobserve(this.refs.node)
|
2018-01-17 04:34:09 +00:00
|
|
|
}
|
|
|
|
intersectionObserver.observe(this.refs.node)
|
|
|
|
},
|
|
|
|
ondestroy() {
|
2018-01-18 02:35:27 +00:00
|
|
|
let key = this.get('key')
|
|
|
|
if (!this.get('unobserved')) {
|
|
|
|
intersectionObserver.unobserve(this.refs.node)
|
|
|
|
}
|
|
|
|
delete onIntersectionCallbacks[key]
|
|
|
|
delete updateItemHeights[key]
|
2018-01-15 18:54:02 +00:00
|
|
|
},
|
2018-01-18 02:35:27 +00:00
|
|
|
data: () => ({
|
|
|
|
unobserved: false
|
|
|
|
}),
|
2018-01-17 04:34:09 +00:00
|
|
|
store: () => virtualListStore,
|
|
|
|
computed: {
|
|
|
|
'shown': ($itemHeights, key) => $itemHeights[key] > 0
|
|
|
|
}
|
2018-01-15 18:54:02 +00:00
|
|
|
}
|
|
|
|
</script>
|