<slot></slot> <script> import { virtualListStore } from './virtualListStore' import throttle from 'lodash-es/throttle' import { isFullscreen, attachFullscreenListener, detachFullscreenListener } from '../../_utils/fullscreen' import { mark, stop } from '../../_utils/marks' import { scheduleIdleTask } from '../../_utils/scheduleIdleTask' import { isMobile } from '../../_utils/isMobile' import { doubleRAF } from '../../_utils/doubleRAF' const SCROLL_EVENT_DELAY = 300 export default { oncreate () { mark('onCreate VirtualListContainer') let { realm, containerQuery } = this.get() this.store.setCurrentRealm(realm) let node = document.querySelector(containerQuery) this.setupScroll(node) this.setupFullscreen() let { scrollTop } = this.store.get() if (scrollTop > 0) { this.observe('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight => { console.log('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight) let { initializedScrollTop } = this.get() if (!initializedScrollTop && allVisibleItemsHaveHeight && node) { this.set({'initializedScrollTop': true}) mark('set scrollTop') console.log('forcing scroll top to ', scrollTop) node.scrollTop = scrollTop stop('set scrollTop') doubleRAF(() => { console.log('initialized VirtualList') this.fire('initialized') }) } }) } else { this.fire('noNeedToScroll') this.observe('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight => { if (allVisibleItemsHaveHeight) { console.log('initialized VirtualList') this.fire('initialized') } }) this.store.setForRealm({ scrollHeight: node.scrollHeight, offsetHeight: node.offsetHeight }) } stop('onCreate VirtualListContainer') }, ondestroy () { this.teardownScroll() this.teardownFullscreen() this.store.setCurrentRealm(null) }, store: () => virtualListStore, methods: { setupScroll (node) { if (!node) { return } this.scrollListener = throttle(event => { let { fullscreen } = this.get() if (fullscreen) { return } this.onScroll(event) }, SCROLL_EVENT_DELAY, { leading: true, trailing: true }) node.addEventListener('scroll', this.scrollListener) }, teardownScroll () { let { containerQuery } = this.get() let node = document.querySelector(containerQuery) if (node) { node.removeEventListener('scroll', this.scrollListener) } }, setupFullscreen () { this.onFullscreenChange = this.onFullscreenChange.bind(this) attachFullscreenListener(this.onFullscreenChange) }, teardownFullscreen () { detachFullscreenListener(this.onFullscreenChange) }, onScroll (event) { let { scrollTop, scrollHeight } = event.target // On mobile devices, this can make scrolling more responsive. On // desktop browsers... it's probably overkill, and can lead to a // checkerboarding issue ("I just scrolled, why is it blank for 5 seconds?"). let runTask = isMobile() ? scheduleIdleTask : requestAnimationFrame runTask(() => { mark('onScroll -> setForRealm()') this.store.setForRealm({scrollTop, scrollHeight}) stop('onScroll -> setForRealm()') }) }, onFullscreenChange () { mark('onFullscreenChange') console.log('is fullscreen? ', isFullscreen()) this.set({ fullscreen: isFullscreen() }) stop('onFullscreenChange') } }, computed: { // TODO: bug in svelte/store – the observer in oncreate() never get removed without this hack allVisibleItemsHaveHeight: ($allVisibleItemsHaveHeight) => $allVisibleItemsHaveHeight } } </script>