1import Vue from 'vue' 2import { ItemProps, SlotProps } from './props' 3 4const Wrapper = { 5 created() { 6 this.shapeKey = this.horizontal ? 'offsetWidth' : 'offsetHeight' 7 }, 8 9 mounted() { 10 if (typeof ResizeObserver !== 'undefined') { 11 this.resizeObserver = new ResizeObserver(() => { 12 this.dispatchSizeChange() 13 }) 14 this.resizeObserver.observe(this.$el) 15 } 16 }, 17 18 // since component will be reused, so dispatch when updated 19 updated() { 20 this.dispatchSizeChange() 21 }, 22 23 beforeDestroy() { 24 if (this.resizeObserver) { 25 this.resizeObserver.disconnect() 26 this.resizeObserver = null 27 } 28 }, 29 30 methods: { 31 getCurrentSize() { 32 return this.$el ? this.$el[this.shapeKey] : 0 33 }, 34 35 // tell parent current size identify by unique key 36 dispatchSizeChange() { 37 this.$parent.$emit(this.event, this.uniqueKey, this.getCurrentSize(), this.hasInitial) 38 } 39 } 40} 41 42// wrapping for item 43export const Item = Vue.component('virtual-list-item', { 44 mixins: [Wrapper], 45 46 props: ItemProps, 47 48 render(h) { 49 const { tag, component, extraProps = {}, index, scopedSlots = {}, uniqueKey } = this 50 extraProps.source = this.source 51 extraProps.index = index 52 53 return h(tag, { 54 key: uniqueKey, 55 attrs: { 56 role: 'item' 57 } 58 }, [h(component, { 59 props: extraProps, 60 scopedSlots: scopedSlots 61 })]) 62 } 63}) 64 65// wrapping for slot 66export const Slot = Vue.component('virtual-list-slot', { 67 mixins: [Wrapper], 68 69 props: SlotProps, 70 71 render(h) { 72 const { tag, uniqueKey } = this 73 74 return h(tag, { 75 key: uniqueKey, 76 attrs: { 77 role: uniqueKey 78 } 79 }, this.$slots.default) 80 } 81})