try to calculate list offset
This commit is contained in:
parent
ec73ce8149
commit
37cf2ac60c
|
@ -1,4 +1,6 @@
|
|||
<div class="pseudo-virtual-list {{shown ? '' : 'hidden'}}" on:initializedVisibleItems ref:node>
|
||||
<div class="pseudo-virtual-list {{shown ? '' : 'hidden'}}"
|
||||
on:initializedVisibleItems
|
||||
ref:node>
|
||||
{{#if wrappedItems}}
|
||||
{{#each wrappedItems as wrappedItem, i @item}}
|
||||
<PseudoVirtualListLazyItem
|
||||
|
@ -22,9 +24,8 @@
|
|||
}
|
||||
</style>
|
||||
<script>
|
||||
|
||||
import PseudoVirtualListLazyItem from './PseudoVirtualListLazyItem.html'
|
||||
import { getRectFromEntry } from '../../_utils/getRectFromEntry'
|
||||
import { getRectFromEntry, getRootRectFromEntry } from '../../_utils/getRectFromEntry'
|
||||
import { mark, stop } from '../../_utils/marks'
|
||||
import { pseudoVirtualListStore } from './pseudoVirtualListStore'
|
||||
|
||||
|
@ -42,8 +43,9 @@
|
|||
}
|
||||
this.store.setForRealm({intersectionStates: intersectionStates})
|
||||
|
||||
let container = document.querySelector(this.get('containerQuery'))
|
||||
let intersectionObserver = new IntersectionObserver(this.onIntersection.bind(this), {
|
||||
root: document.querySelector(this.get('containerQuery')),
|
||||
root: container,
|
||||
rootMargin: '300% 0px'
|
||||
})
|
||||
this.set({intersectionObserver})
|
||||
|
@ -55,6 +57,8 @@
|
|||
this.fire('initializedVisibleItems')
|
||||
}
|
||||
})
|
||||
|
||||
this.calculateListOffset()
|
||||
stop('PseudoVirtualList oncreate()')
|
||||
},
|
||||
ondestroy() {
|
||||
|
@ -114,6 +118,21 @@
|
|||
intersectionStates = Object.assign(intersectionStates, newIntersectionStates)
|
||||
this.store.setForRealm({intersectionStates: intersectionStates})
|
||||
stop('onIntersection')
|
||||
},
|
||||
calculateListOffset() {
|
||||
let node = this.refs.node
|
||||
let container = document.querySelector(this.get('containerQuery'))
|
||||
let containerObserver = new IntersectionObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
let rect = getRectFromEntry(entry)
|
||||
let rootRect = getRootRectFromEntry(entry, container)
|
||||
let listOffset = rect.top - rootRect.top
|
||||
console.log('listOffset', listOffset)
|
||||
this.store.setForRealm({listOffset})
|
||||
})
|
||||
containerObserver.disconnect()
|
||||
}, {root: container})
|
||||
containerObserver.observe(node)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<VirtualListContainer :realm :containerQuery >
|
||||
<div class="virtual-list {{shown ? '' : 'hidden'}}" style="height: {{$height}}px;">
|
||||
<div class="virtual-list {{shown ? '' : 'hidden'}}"
|
||||
style="height: {{$height}}px;"
|
||||
ref:node >
|
||||
<VirtualListHeader component="{{headerComponent}}" virtualProps="{{headerProps}}" shown="{{$showHeader}}"/>
|
||||
{{#if $visibleItems}}
|
||||
{{#each $visibleItems as visibleItem @key}}
|
||||
|
@ -31,6 +33,7 @@
|
|||
import throttle from 'lodash/throttle'
|
||||
import { mark, stop } from '../../_utils/marks'
|
||||
import isEqual from 'lodash/isEqual'
|
||||
import { getRectFromEntry, getRootRectFromEntry } from '../../_utils/getRectFromEntry'
|
||||
|
||||
const DISTANCE_FROM_BOTTOM_TO_FIRE = 800
|
||||
const SCROLL_EVENT_THROTTLE = 1000
|
||||
|
@ -86,6 +89,8 @@
|
|||
this.fireScrollToTop()
|
||||
}
|
||||
})
|
||||
|
||||
this.calculateListOffset()
|
||||
},
|
||||
data: () => ({
|
||||
component: null
|
||||
|
@ -104,6 +109,27 @@
|
|||
scrollTop: ($scrollTop) => $scrollTop,
|
||||
// TODO: bug in svelte store, shouldn't need to do this
|
||||
allVisibleItemsHaveHeight: ($allVisibleItemsHaveHeight) => $allVisibleItemsHaveHeight,
|
||||
},
|
||||
methods: {
|
||||
calculateListOffset() {
|
||||
let node = this.refs.node
|
||||
let container = document.querySelector(this.get('containerQuery'))
|
||||
|
||||
// TODO: this needs to dynamically update, e.g. after pinned
|
||||
// toots are rendered and thus the distance between the .container
|
||||
// and the .virtual-list has changed.
|
||||
let containerObserver = new IntersectionObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
let rect = getRectFromEntry(entry)
|
||||
let rootRect = getRootRectFromEntry(entry, container)
|
||||
let listOffset = rect.top - rootRect.top
|
||||
console.log('listOffset', listOffset)
|
||||
this.store.setForRealm({listOffset})
|
||||
})
|
||||
containerObserver.disconnect()
|
||||
}, {root: container})
|
||||
containerObserver.observe(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -20,16 +20,20 @@ virtualListStore.computeForRealm('headerHeight', 0)
|
|||
virtualListStore.computeForRealm('scrollTop', 0)
|
||||
virtualListStore.computeForRealm('scrollHeight', 0)
|
||||
virtualListStore.computeForRealm('offsetHeight', 0)
|
||||
virtualListStore.computeForRealm('listOffset', 0)
|
||||
virtualListStore.computeForRealm('itemHeights', {})
|
||||
|
||||
virtualListStore.compute('rawVisibleItems',
|
||||
['items', 'scrollTop', 'itemHeights', 'offsetHeight', 'showHeader', 'headerHeight'],
|
||||
(items, scrollTop, itemHeights, offsetHeight, showHeader, headerHeight) => {
|
||||
['items', 'scrollTop', 'itemHeights', 'offsetHeight', 'showHeader', 'headerHeight', 'listOffset'],
|
||||
(items, scrollTop, itemHeights, offsetHeight, showHeader, headerHeight, listOffset) => {
|
||||
window.rawVisibleItemsComputed = (window.rawVisibleItemsComputed || 0) + 1
|
||||
mark('compute visibleItems')
|
||||
if (!items) {
|
||||
return null
|
||||
}
|
||||
// listOffset is the offset of the entire list within its scrollable container,
|
||||
// so the effective scrollTop is what the "real" scrollTop is relative to the list.
|
||||
let effectiveScrollTop = scrollTop - listOffset
|
||||
let renderBuffer = RENDER_BUFFER_FACTOR * offsetHeight
|
||||
let visibleItems = []
|
||||
let totalOffset = showHeader ? headerHeight : 0
|
||||
|
@ -40,13 +44,13 @@ virtualListStore.compute('rawVisibleItems',
|
|||
let height = itemHeights[key] || 0
|
||||
let currentOffset = totalOffset
|
||||
totalOffset += height
|
||||
let isAboveViewport = (currentOffset < scrollTop)
|
||||
let isAboveViewport = (currentOffset < effectiveScrollTop)
|
||||
if (isAboveViewport) {
|
||||
if ((scrollTop - height - renderBuffer) > currentOffset) {
|
||||
if ((effectiveScrollTop - height - renderBuffer) > currentOffset) {
|
||||
continue // above the area we want to render
|
||||
}
|
||||
} else {
|
||||
if (currentOffset > (scrollTop + offsetHeight + renderBuffer)) {
|
||||
if (currentOffset > (effectiveScrollTop + offsetHeight + renderBuffer)) {
|
||||
break // below the area we want to render
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
export default {
|
||||
oncreate() {
|
||||
let accountId = this.get('params').accountId
|
||||
let instanceName = this.store.get('currentInstance')
|
||||
updateProfileAndRelationship(accountId)
|
||||
},
|
||||
store: () => store,
|
||||
|
|
|
@ -3,16 +3,29 @@
|
|||
|
||||
let hasBoundingRectBug
|
||||
|
||||
function rectsAreEqual(rectA, rectB) {
|
||||
return rectA.height === rectB.height &&
|
||||
rectA.top === rectB.top &&
|
||||
rectA.width === rectB.width &&
|
||||
rectA.bottom === rectB.bottom &&
|
||||
rectA.left === rectB.left &&
|
||||
rectA.right === rectB.right
|
||||
}
|
||||
|
||||
export function getRectFromEntry (entry) {
|
||||
if (typeof hasBoundingRectBug !== 'boolean') {
|
||||
const boundingRect = entry.target.getBoundingClientRect()
|
||||
const observerRect = entry.boundingClientRect
|
||||
hasBoundingRectBug = boundingRect.height !== observerRect.height ||
|
||||
boundingRect.top !== observerRect.top ||
|
||||
boundingRect.width !== observerRect.width ||
|
||||
boundingRect.bottom !== observerRect.bottom ||
|
||||
boundingRect.left !== observerRect.left ||
|
||||
boundingRect.right !== observerRect.right
|
||||
hasBoundingRectBug = !rectsAreEqual(boundingRect, observerRect)
|
||||
}
|
||||
return hasBoundingRectBug ? entry.target.getBoundingClientRect() : entry.boundingClientRect
|
||||
}
|
||||
|
||||
export function getRootRectFromEntry (entry, root) {
|
||||
if (typeof hasBoundingRectBug !== 'boolean') {
|
||||
const boundingRect = root.getBoundingClientRect()
|
||||
const rootRect = entry.rootBounds
|
||||
hasBoundingRectBug = !rectsAreEqual(boundingRect, rootRect)
|
||||
}
|
||||
return hasBoundingRectBug ? root.getBoundingClientRect() : entry.rootBounds
|
||||
}
|
Loading…
Reference in New Issue