|
1 | | -import { defineComponent, h } from 'vue'; |
| 1 | +import { |
| 2 | + computed, |
| 3 | + defineComponent, |
| 4 | + onMounted, |
| 5 | + onUnmounted, |
| 6 | + onUpdated, |
| 7 | + ref, |
| 8 | + Ref, |
| 9 | +} from 'vue'; |
| 10 | +// TODO: remove this |
2 | 11 | import emitter from 'tiny-emitter/instance'; |
3 | 12 | import { ItemProps, SlotProps } from './props'; |
4 | 13 |
|
5 | | -const Wrapper = { |
6 | | - created() { |
7 | | - this.shapeKey = this.horizontal ? 'offsetWidth' : 'offsetHeight'; |
8 | | - }, |
| 14 | +const useResizeChange = (props: any, rootRef: Ref<HTMLElement | null>) => { |
| 15 | + let resizeObserver: ResizeObserver | null = null; |
| 16 | + const shapeKey = computed(() => |
| 17 | + props.horizontal ? 'offsetWidth' : 'offsetHeight', |
| 18 | + ); |
| 19 | + |
| 20 | + const getCurrentSize = () => { |
| 21 | + return rootRef.value ? rootRef.value[shapeKey.value] : 0; |
| 22 | + }; |
9 | 23 |
|
10 | | - mounted() { |
| 24 | + // tell parent current size identify by unqiue key |
| 25 | + const dispatchSizeChange = () => { |
| 26 | + const { event, uniqueKey, hasInitial } = props; |
| 27 | + console.log(getCurrentSize()); |
| 28 | + emitter.emit(event, uniqueKey, getCurrentSize(), hasInitial); |
| 29 | + }; |
| 30 | + |
| 31 | + onMounted(() => { |
11 | 32 | if (typeof ResizeObserver !== 'undefined') { |
12 | | - this.resizeObserver = new ResizeObserver(() => { |
13 | | - this.dispatchSizeChange(); |
| 33 | + resizeObserver = new ResizeObserver(() => { |
| 34 | + dispatchSizeChange(); |
14 | 35 | }); |
15 | | - this.resizeObserver.observe(this.$el); |
| 36 | + rootRef.value && resizeObserver.observe(rootRef.value); |
16 | 37 | } |
17 | | - }, |
| 38 | + }); |
18 | 39 |
|
19 | | - // since componet will be reused, so disptach when updated |
20 | | - updated() { |
21 | | - this.dispatchSizeChange(); |
22 | | - }, |
| 40 | + onUpdated(() => { |
| 41 | + dispatchSizeChange(); |
| 42 | + }); |
23 | 43 |
|
24 | | - beforeDestroy() { |
25 | | - if (this.resizeObserver) { |
26 | | - this.resizeObserver.disconnect(); |
27 | | - this.resizeObserver = null; |
| 44 | + onUnmounted(() => { |
| 45 | + if (resizeObserver) { |
| 46 | + resizeObserver.disconnect(); |
| 47 | + resizeObserver = null; |
28 | 48 | } |
29 | | - }, |
30 | | - |
31 | | - methods: { |
32 | | - getCurrentSize() { |
33 | | - return this.$el ? this.$el[this.shapeKey] : 0; |
34 | | - }, |
35 | | - |
36 | | - // tell parent current size identify by unqiue key |
37 | | - dispatchSizeChange() { |
38 | | - emitter.emit( |
39 | | - this.event, |
40 | | - this.uniqueKey, |
41 | | - this.getCurrentSize(), |
42 | | - this.hasInitial, |
43 | | - ); |
44 | | - // this.$parent.$emit(this.event, this.uniqueKey, this.getCurrentSize(), this.hasInitial) |
45 | | - }, |
46 | | - }, |
| 49 | + }); |
47 | 50 | }; |
48 | 51 |
|
49 | 52 | export const Item = defineComponent({ |
50 | 53 | name: 'VirtualListItem', |
51 | | - mixins: [Wrapper], |
52 | 54 | props: ItemProps, |
53 | | - render() { |
54 | | - const { |
55 | | - tag, |
56 | | - component, |
57 | | - extraProps = {}, |
58 | | - index, |
59 | | - source, |
60 | | - scopedSlots = {}, |
61 | | - uniqueKey, |
62 | | - } = this; |
63 | | - const props = { |
64 | | - ...extraProps, |
65 | | - source, |
66 | | - index, |
67 | | - }; |
| 55 | + setup(props) { |
| 56 | + const rootRef = ref<HTMLElement | null>(null); |
| 57 | + useResizeChange(props, rootRef); |
| 58 | + |
| 59 | + return () => { |
| 60 | + const { |
| 61 | + tag: Tag, |
| 62 | + component: Comp, |
| 63 | + extraProps = {}, |
| 64 | + index, |
| 65 | + source, |
| 66 | + scopedSlots = {}, |
| 67 | + uniqueKey, |
| 68 | + } = props; |
| 69 | + const mergedProps = { |
| 70 | + ...extraProps, |
| 71 | + source, |
| 72 | + index, |
| 73 | + }; |
68 | 74 |
|
69 | | - return h( |
70 | | - tag, |
71 | | - { |
72 | | - key: uniqueKey, |
73 | | - }, |
74 | | - [ |
75 | | - h(component, { |
76 | | - ...props, |
77 | | - scopedSlots: scopedSlots, |
78 | | - }), |
79 | | - ], |
80 | | - ); |
| 75 | + return ( |
| 76 | + <Tag key={uniqueKey} ref={rootRef}> |
| 77 | + <Comp {...mergedProps} scopedSlots={scopedSlots} /> |
| 78 | + </Tag> |
| 79 | + ); |
| 80 | + }; |
81 | 81 | }, |
82 | 82 | }); |
83 | 83 |
|
84 | 84 | export const Slot = defineComponent({ |
85 | | - mixins: [Wrapper], |
| 85 | + name: 'VirtualListSlot', |
86 | 86 | props: SlotProps, |
87 | 87 | setup(props, { slots }) { |
| 88 | + const rootRef = ref<HTMLElement | null>(null); |
| 89 | + useResizeChange(props, rootRef); |
| 90 | + |
88 | 91 | return () => { |
89 | | - const { tag, uniqueKey } = props; |
| 92 | + const { tag: Tag, uniqueKey } = props; |
90 | 93 |
|
91 | | - return h( |
92 | | - tag, |
93 | | - { |
94 | | - key: uniqueKey, |
95 | | - }, |
96 | | - slots.default(), |
| 94 | + return ( |
| 95 | + <Tag ref={rootRef} key={uniqueKey}> |
| 96 | + {slots.default?.()} |
| 97 | + </Tag> |
97 | 98 | ); |
98 | 99 | }; |
99 | 100 | }, |
|
0 commit comments