implement AsyncLayout
This commit is contained in:
		
							parent
							
								
									b58033203d
								
							
						
					
					
						commit
						0f69df592a
					
				
					 2 changed files with 36 additions and 22 deletions
				
			
		| 
						 | 
				
			
			@ -20,28 +20,20 @@
 | 
			
		|||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
  import { virtualListStore } from '../_utils/virtualListStore'
 | 
			
		||||
  import { AsyncLayout } from '../_utils/AsyncLayout'
 | 
			
		||||
  import { mark, stop } from '../_utils/marks'
 | 
			
		||||
 | 
			
		||||
  let updateItemHeights = {}
 | 
			
		||||
  let promise = Promise.resolve()
 | 
			
		||||
  let onIntersectionCallbacks = {}
 | 
			
		||||
 | 
			
		||||
  let intersectionObserver = new IntersectionObserver(entries => {
 | 
			
		||||
    entries.forEach(entry => {
 | 
			
		||||
      let key = entry.target.getAttribute('virtual-list-key')
 | 
			
		||||
      onIntersectionCallbacks[key](entry)
 | 
			
		||||
    })
 | 
			
		||||
  })
 | 
			
		||||
  const asyncLayout = new AsyncLayout(node => node.getAttribute('virtual-list-key'))
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
      let key = this.get('key')
 | 
			
		||||
      // TODO: implement AsyncLayout
 | 
			
		||||
      // TODO: implement batchUpdate
 | 
			
		||||
      // TODO: fix resize on media
 | 
			
		||||
      onIntersectionCallbacks[key] = entry => {
 | 
			
		||||
        console.log('onIntersection', key, entry.boundingClientRect.height)
 | 
			
		||||
        let rect = entry.boundingClientRect
 | 
			
		||||
      asyncLayout.observe(key, this.refs.node, (rect) => {
 | 
			
		||||
        updateItemHeights[key] = rect.height
 | 
			
		||||
        promise = promise.then(() => {
 | 
			
		||||
          // update all item heights in one microtask batch for better perf
 | 
			
		||||
| 
						 | 
				
			
			@ -61,22 +53,13 @@
 | 
			
		|||
          updateItemHeights = {}
 | 
			
		||||
          stop('batch update VirtualListItem')
 | 
			
		||||
        })
 | 
			
		||||
        this.set({ unobserved: true })
 | 
			
		||||
        intersectionObserver.unobserve(this.refs.node)
 | 
			
		||||
      }
 | 
			
		||||
      intersectionObserver.observe(this.refs.node)
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    ondestroy() {
 | 
			
		||||
      let key = this.get('key')
 | 
			
		||||
      if (!this.get('unobserved')) {
 | 
			
		||||
        intersectionObserver.unobserve(this.refs.node)
 | 
			
		||||
      }
 | 
			
		||||
      delete onIntersectionCallbacks[key]
 | 
			
		||||
      asyncLayout.unobserve(key, this.refs.node)
 | 
			
		||||
      delete updateItemHeights[key]
 | 
			
		||||
    },
 | 
			
		||||
    data: () => ({
 | 
			
		||||
      unobserved: false
 | 
			
		||||
    }),
 | 
			
		||||
    store: () => virtualListStore,
 | 
			
		||||
    computed: {
 | 
			
		||||
      'shown': ($itemHeights, key) => $itemHeights[key] > 0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										31
									
								
								routes/_utils/AsyncLayout.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								routes/_utils/AsyncLayout.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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…
	
	Add table
		
		Reference in a new issue