calculate listOffset to avoid profile offset issue

This commit is contained in:
Nolan Lawson 2018-03-22 17:33:42 -07:00
parent 98b8ea1c67
commit ef51842e6a
4 changed files with 35 additions and 14 deletions

View File

@ -1,5 +1,7 @@
<VirtualListContainer :realm :containerQuery > <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}}"/> <VirtualListHeader component="{{headerComponent}}" virtualProps="{{headerProps}}" shown="{{$showHeader}}"/>
{{#if $visibleItems}} {{#if $visibleItems}}
{{#each $visibleItems as visibleItem @key}} {{#each $visibleItems as visibleItem @key}}
@ -85,6 +87,7 @@
if (scrollTop === 0) { if (scrollTop === 0) {
this.fireScrollToTop() this.fireScrollToTop()
} }
this.calculateListOffset()
}) })
}, },
data: () => ({ data: () => ({
@ -104,6 +107,19 @@
scrollTop: ($scrollTop) => $scrollTop, scrollTop: ($scrollTop) => $scrollTop,
// TODO: bug in svelte store, shouldn't need to do this // TODO: bug in svelte store, shouldn't need to do this
allVisibleItemsHaveHeight: ($allVisibleItemsHaveHeight) => $allVisibleItemsHaveHeight, allVisibleItemsHaveHeight: ($allVisibleItemsHaveHeight) => $allVisibleItemsHaveHeight,
},
methods: {
calculateListOffset() {
// TODO: better way to get the offset top?
let node = this.refs.node
if (!node) {
return
}
mark('calculateListOffset')
let listOffset = node.offsetParent.offsetTop
this.store.setForRealm({listOffset})
stop('calculateListOffset')
}
} }
} }
</script> </script>

View File

@ -2,7 +2,7 @@ import { mark, stop } from '../../_utils/marks'
import { RealmStore } from '../../_utils/RealmStore' import { RealmStore } from '../../_utils/RealmStore'
import { reselect } from '../../_utils/reselect' import { reselect } from '../../_utils/reselect'
const RENDER_BUFFER_FACTOR = 5 const RENDER_BUFFER_FACTOR = 1.5
class VirtualListStore extends RealmStore { class VirtualListStore extends RealmStore {
constructor (state) { constructor (state) {
@ -20,16 +20,18 @@ virtualListStore.computeForRealm('headerHeight', 0)
virtualListStore.computeForRealm('scrollTop', 0) virtualListStore.computeForRealm('scrollTop', 0)
virtualListStore.computeForRealm('scrollHeight', 0) virtualListStore.computeForRealm('scrollHeight', 0)
virtualListStore.computeForRealm('offsetHeight', 0) virtualListStore.computeForRealm('offsetHeight', 0)
virtualListStore.computeForRealm('listOffset', 0)
virtualListStore.computeForRealm('itemHeights', {}) virtualListStore.computeForRealm('itemHeights', {})
virtualListStore.compute('rawVisibleItems', virtualListStore.compute('rawVisibleItems',
['items', 'scrollTop', 'itemHeights', 'offsetHeight', 'showHeader', 'headerHeight'], ['items', 'scrollTop', 'itemHeights', 'offsetHeight', 'showHeader', 'headerHeight', 'listOffset'],
(items, scrollTop, itemHeights, offsetHeight, showHeader, headerHeight) => { (items, scrollTop, itemHeights, offsetHeight, showHeader, headerHeight, listOffset) => {
window.rawVisibleItemsComputed = (window.rawVisibleItemsComputed || 0) + 1 window.rawVisibleItemsComputed = (window.rawVisibleItemsComputed || 0) + 1
mark('compute visibleItems') mark('compute visibleItems')
if (!items) { if (!items) {
return null return null
} }
let effectiveScrollTop = scrollTop - listOffset
let renderBuffer = RENDER_BUFFER_FACTOR * offsetHeight let renderBuffer = RENDER_BUFFER_FACTOR * offsetHeight
let visibleItems = [] let visibleItems = []
let totalOffset = showHeader ? headerHeight : 0 let totalOffset = showHeader ? headerHeight : 0
@ -40,13 +42,13 @@ virtualListStore.compute('rawVisibleItems',
let height = itemHeights[key] || 0 let height = itemHeights[key] || 0
let currentOffset = totalOffset let currentOffset = totalOffset
totalOffset += height totalOffset += height
let isAboveViewport = (currentOffset < scrollTop) let isAboveViewport = (currentOffset < effectiveScrollTop)
if (isAboveViewport) { if (isAboveViewport) {
if ((scrollTop - height - renderBuffer) > currentOffset) { if ((effectiveScrollTop - height - renderBuffer) > currentOffset) {
continue // above the area we want to render continue // above the area we want to render
} }
} else { } else {
if (currentOffset > (scrollTop + offsetHeight + renderBuffer)) { if (currentOffset > (effectiveScrollTop + offsetHeight + renderBuffer)) {
break // below the area we want to render break // below the area we want to render
} }
} }

View File

@ -30,7 +30,6 @@
export default { export default {
oncreate() { oncreate() {
let accountId = this.get('params').accountId let accountId = this.get('params').accountId
let instanceName = this.store.get('currentInstance')
updateProfileAndRelationship(accountId) updateProfileAndRelationship(accountId)
}, },
store: () => store, store: () => store,

View File

@ -3,16 +3,20 @@
let hasBoundingRectBug 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) { export function getRectFromEntry (entry) {
if (typeof hasBoundingRectBug !== 'boolean') { if (typeof hasBoundingRectBug !== 'boolean') {
const boundingRect = entry.target.getBoundingClientRect() const boundingRect = entry.target.getBoundingClientRect()
const observerRect = entry.boundingClientRect const observerRect = entry.boundingClientRect
hasBoundingRectBug = boundingRect.height !== observerRect.height || hasBoundingRectBug = !rectsAreEqual(boundingRect, observerRect)
boundingRect.top !== observerRect.top ||
boundingRect.width !== observerRect.width ||
boundingRect.bottom !== observerRect.bottom ||
boundingRect.left !== observerRect.left ||
boundingRect.right !== observerRect.right
} }
return hasBoundingRectBug ? entry.target.getBoundingClientRect() : entry.boundingClientRect return hasBoundingRectBug ? entry.target.getBoundingClientRect() : entry.boundingClientRect
} }