-
-
Notifications
You must be signed in to change notification settings - Fork 52
/
VList.tsx
144 lines (137 loc) · 4.16 KB
/
VList.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/** @jsxImportSource vue */
import {
defineComponent,
ComponentOptionsMixin,
SlotsType,
ComponentOptionsWithObjectProps,
ComponentObjectPropsOptions,
ref,
} from "vue";
import { Virtualizer, VirtualizerHandle } from "./Virtualizer";
interface VListHandle extends VirtualizerHandle {}
const props = {
/**
* The data items rendered by this component.
*/
data: { type: Array, required: true },
/**
* Number of items to render above/below the visible bounds of the list. You can increase to avoid showing blank items in fast scrolling.
* @defaultValue 4
*/
overscan: { type: Number, default: 4 },
/**
* Item size hint for unmeasured items. It will help to reduce scroll jump when items are measured if used properly.
*
* - If not set, initial item sizes will be automatically estimated from measured sizes. This is recommended for most cases.
* - If set, you can opt out estimation and use the value as initial item size.
*/
itemSize: Number,
/**
* While true is set, scroll position will be maintained from the end not usual start when items are added to/removed from start. It's recommended to set false if you add to/remove from mid/end of the list because it can cause unexpected behavior. This prop is useful for reverse infinite scrolling.
*/
shift: Boolean,
/**
* If true, rendered as a horizontally scrollable list. Otherwise rendered as a vertically scrollable list.
*/
horizontal: Boolean,
/**
* A prop for SSR. If set, the specified amount of items will be mounted in the initial rendering regardless of the container size until hydrated.
*/
ssrCount: Number,
} satisfies ComponentObjectPropsOptions;
export const VList = /*#__PURE__*/ defineComponent({
props: props,
emits: ["scroll", "scrollEnd", "rangeChange"],
setup(props, { emit, expose, slots }) {
const horizontal = props.horizontal;
const onScroll = (offset: number) => {
emit("scroll", offset);
};
const onScrollEnd = () => {
emit("scrollEnd");
};
const onRangeChange = (start: number, end: number) => {
emit("rangeChange", start, end);
};
const handle = ref<InstanceType<typeof Virtualizer>>();
expose({
get scrollOffset() {
return handle.value!.scrollOffset;
},
get scrollSize() {
return handle.value!.scrollSize;
},
get viewportSize() {
return handle.value!.viewportSize;
},
getItemOffset: (...args) => handle.value!.getItemOffset(...args),
scrollToIndex: (...args) => handle.value!.scrollToIndex(...args),
scrollTo: (...args) => handle.value!.scrollTo(...args),
scrollBy: (...args) => handle.value!.scrollBy(...args),
} satisfies VListHandle);
return () => {
return (
<div
style={{
display: horizontal ? "inline-block" : "block",
[horizontal ? "overflowX" : "overflowY"]: "auto",
contain: "strict",
width: "100%",
height: "100%",
}}
>
<Virtualizer
ref={handle}
data={props.data}
overscan={props.overscan}
itemSize={props.itemSize}
shift={props.shift}
ssrCount={props.ssrCount}
horizontal={horizontal}
onScroll={onScroll}
onScrollEnd={onScrollEnd}
onRangeChange={onRangeChange}
>
{slots}
</Virtualizer>
</div>
);
};
},
} as ComponentOptionsWithObjectProps<
typeof props,
VListHandle,
{},
{},
{},
ComponentOptionsMixin,
ComponentOptionsMixin,
{
/**
* Callback invoked whenever scroll offset changes.
* @param offset Current scrollTop or scrollLeft.
*/
scroll: (offset: number) => void;
/**
* Callback invoked when scrolling stops.
*/
scrollEnd: () => void;
/**
* Callback invoked when visible items range changes.
*/
rangeChange: (
/**
* The start index of viewable items.
*/
startIndex: number,
/**
* The end index of viewable items.
*/
endIndex: number
) => void;
},
string,
{},
string,
SlotsType<{ default: any }>
>);