calculate listOffset to avoid profile offset issue
This commit is contained in:
		
							parent
							
								
									98b8ea1c67
								
							
						
					
					
						commit
						ef51842e6a
					
				
					 4 changed files with 35 additions and 14 deletions
				
			
		| 
						 | 
				
			
			@ -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}}
 | 
			
		||||
| 
						 | 
				
			
			@ -85,6 +87,7 @@
 | 
			
		|||
        if (scrollTop === 0) {
 | 
			
		||||
          this.fireScrollToTop()
 | 
			
		||||
        }
 | 
			
		||||
        this.calculateListOffset()
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    data: () => ({
 | 
			
		||||
| 
						 | 
				
			
			@ -104,6 +107,19 @@
 | 
			
		|||
      scrollTop: ($scrollTop) => $scrollTop,
 | 
			
		||||
      // TODO: bug in svelte store, shouldn't need to do this
 | 
			
		||||
      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>
 | 
			
		||||
| 
						 | 
				
			
			@ -2,7 +2,7 @@ import { mark, stop } from '../../_utils/marks'
 | 
			
		|||
import { RealmStore } from '../../_utils/RealmStore'
 | 
			
		||||
import { reselect } from '../../_utils/reselect'
 | 
			
		||||
 | 
			
		||||
const RENDER_BUFFER_FACTOR = 5
 | 
			
		||||
const RENDER_BUFFER_FACTOR = 1.5
 | 
			
		||||
 | 
			
		||||
class VirtualListStore extends RealmStore {
 | 
			
		||||
  constructor (state) {
 | 
			
		||||
| 
						 | 
				
			
			@ -20,16 +20,18 @@ 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
 | 
			
		||||
      }
 | 
			
		||||
      let effectiveScrollTop = scrollTop - listOffset
 | 
			
		||||
      let renderBuffer = RENDER_BUFFER_FACTOR * offsetHeight
 | 
			
		||||
      let visibleItems = []
 | 
			
		||||
      let totalOffset = showHeader ? headerHeight : 0
 | 
			
		||||
| 
						 | 
				
			
			@ -40,13 +42,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,20 @@
 | 
			
		|||
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue