@v-c/virtual-list 0.0.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Filler.cjs +51 -1
- package/dist/Filler.js +47 -56
- package/dist/Item.cjs +26 -1
- package/dist/Item.js +23 -26
- package/dist/List.cjs +412 -1
- package/dist/List.d.ts +45 -9
- package/dist/List.js +407 -274
- package/dist/ScrollBar.cjs +259 -1
- package/dist/ScrollBar.d.ts +3 -97
- package/dist/ScrollBar.js +254 -191
- package/dist/_virtual/rolldown_runtime.cjs +21 -0
- package/dist/hooks/useDiffItem.cjs +19 -1
- package/dist/hooks/useDiffItem.js +16 -20
- package/dist/hooks/useFrameWheel.cjs +63 -1
- package/dist/hooks/useFrameWheel.js +60 -51
- package/dist/hooks/useGetSize.cjs +29 -1
- package/dist/hooks/useGetSize.d.ts +2 -2
- package/dist/hooks/useGetSize.js +27 -23
- package/dist/hooks/useHeights.cjs +66 -1
- package/dist/hooks/useHeights.d.ts +1 -1
- package/dist/hooks/useHeights.js +62 -41
- package/dist/hooks/useMobileTouchMove.cjs +82 -1
- package/dist/hooks/useMobileTouchMove.js +79 -43
- package/dist/hooks/useOriginScroll.cjs +23 -1
- package/dist/hooks/useOriginScroll.js +20 -16
- package/dist/hooks/useScrollDrag.cjs +83 -1
- package/dist/hooks/useScrollDrag.js +77 -48
- package/dist/hooks/useScrollTo.cjs +97 -0
- package/dist/hooks/useScrollTo.d.ts +19 -0
- package/dist/hooks/useScrollTo.js +94 -0
- package/dist/index.cjs +4 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -4
- package/dist/interface.cjs +0 -1
- package/dist/interface.d.ts +1 -1
- package/dist/interface.js +0 -1
- package/dist/utils/CacheMap.cjs +25 -1
- package/dist/utils/CacheMap.d.ts +1 -1
- package/dist/utils/CacheMap.js +23 -28
- package/dist/utils/isFirefox.cjs +4 -1
- package/dist/utils/isFirefox.js +2 -4
- package/dist/utils/scrollbarUtil.cjs +8 -1
- package/dist/utils/scrollbarUtil.js +7 -6
- package/package.json +19 -13
- package/docs/basic.vue +0 -175
- package/docs/height.vue +0 -48
- package/docs/nest.vue +0 -60
- package/docs/no-virtual.vue +0 -127
- package/docs/switch.vue +0 -101
- package/docs/virtual-list.stories.vue +0 -31
- package/src/Filler.tsx +0 -72
- package/src/Item.tsx +0 -34
- package/src/List.tsx +0 -577
- package/src/ScrollBar.tsx +0 -298
- package/src/__tests__/List.test.ts +0 -59
- package/src/hooks/useDiffItem.ts +0 -27
- package/src/hooks/useFrameWheel.ts +0 -141
- package/src/hooks/useGetSize.ts +0 -44
- package/src/hooks/useHeights.ts +0 -106
- package/src/hooks/useMobileTouchMove.ts +0 -131
- package/src/hooks/useOriginScroll.ts +0 -47
- package/src/hooks/useScrollDrag.ts +0 -123
- package/src/index.ts +0 -5
- package/src/interface.ts +0 -32
- package/src/utils/CacheMap.ts +0 -42
- package/src/utils/isFirefox.ts +0 -3
- package/src/utils/scrollbarUtil.ts +0 -10
- package/vite.config.ts +0 -18
- package/vitest.config.ts +0 -11
package/package.json
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@v-c/virtual-list",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "1.0.1",
|
|
5
|
+
"description": "Vue Virtual List Component",
|
|
6
|
+
"author": "",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"vue",
|
|
10
|
+
"virtual-list",
|
|
11
|
+
"vue-component"
|
|
12
|
+
],
|
|
5
13
|
"exports": {
|
|
6
14
|
".": {
|
|
7
15
|
"types": "./dist/index.d.ts",
|
|
@@ -11,15 +19,11 @@
|
|
|
11
19
|
"./dist/*": "./dist/*",
|
|
12
20
|
"./package.json": "./package.json"
|
|
13
21
|
},
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"vue",
|
|
19
|
-
"virtual-list",
|
|
20
|
-
"vue-component"
|
|
22
|
+
"main": "./dist/index.js",
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"package.json"
|
|
21
26
|
],
|
|
22
|
-
"main": "index.js",
|
|
23
27
|
"publishConfig": {
|
|
24
28
|
"access": "public"
|
|
25
29
|
},
|
|
@@ -27,12 +31,14 @@
|
|
|
27
31
|
"vue": "^3.0.0"
|
|
28
32
|
},
|
|
29
33
|
"dependencies": {
|
|
30
|
-
"@v-c/resize-observer": "0.0
|
|
31
|
-
"@v-c/util": "
|
|
34
|
+
"@v-c/resize-observer": "^1.0.0",
|
|
35
|
+
"@v-c/util": "^1.0.2"
|
|
32
36
|
},
|
|
33
37
|
"scripts": {
|
|
34
38
|
"build": "vite build",
|
|
35
|
-
"test": "vitest",
|
|
36
|
-
"prepublish": "pnpm build"
|
|
39
|
+
"test": "vitest run",
|
|
40
|
+
"prepublish": "pnpm build",
|
|
41
|
+
"bump": "bumpp",
|
|
42
|
+
"patch": "bumpp --release patch"
|
|
37
43
|
}
|
|
38
44
|
}
|
package/docs/basic.vue
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ref } from 'vue'
|
|
3
|
-
import VirtualList, { type ListRef } from '../src'
|
|
4
|
-
|
|
5
|
-
interface Item {
|
|
6
|
-
id: number
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const data: Item[] = []
|
|
10
|
-
for (let i = 0; i < 1000; i += 1) {
|
|
11
|
-
data.push({ id: i })
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const listRef = ref<ListRef>()
|
|
15
|
-
|
|
16
|
-
function scrollToShowBar() {
|
|
17
|
-
listRef.value?.scrollTo(null)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function scrollTo100px() {
|
|
21
|
-
listRef.value?.scrollTo(500)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function scrollToLarge() {
|
|
25
|
-
listRef.value?.scrollTo({
|
|
26
|
-
index: 99999999,
|
|
27
|
-
align: 'top',
|
|
28
|
-
})
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function scrollTo50Top() {
|
|
32
|
-
listRef.value?.scrollTo({
|
|
33
|
-
index: 50,
|
|
34
|
-
align: 'top',
|
|
35
|
-
})
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function scrollTo50Bottom() {
|
|
39
|
-
listRef.value?.scrollTo({
|
|
40
|
-
index: 50,
|
|
41
|
-
align: 'bottom',
|
|
42
|
-
})
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function scrollTo50Auto() {
|
|
46
|
-
listRef.value?.scrollTo({
|
|
47
|
-
index: 50,
|
|
48
|
-
align: 'auto',
|
|
49
|
-
})
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function scrollTo50TopOffset() {
|
|
53
|
-
listRef.value?.scrollTo({
|
|
54
|
-
index: 50,
|
|
55
|
-
align: 'top',
|
|
56
|
-
offset: 15,
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function scrollTo50BottomOffset() {
|
|
61
|
-
listRef.value?.scrollTo({
|
|
62
|
-
index: 50,
|
|
63
|
-
align: 'bottom',
|
|
64
|
-
offset: 15,
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function scrollToKey50() {
|
|
69
|
-
listRef.value?.scrollTo({
|
|
70
|
-
key: 50,
|
|
71
|
-
align: 'auto',
|
|
72
|
-
})
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function scrollToLast() {
|
|
76
|
-
listRef.value?.scrollTo({
|
|
77
|
-
index: data.length - 2,
|
|
78
|
-
align: 'top',
|
|
79
|
-
})
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function scrollToFirst() {
|
|
83
|
-
listRef.value?.scrollTo({
|
|
84
|
-
index: 0,
|
|
85
|
-
align: 'bottom',
|
|
86
|
-
})
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const visible = ref(true)
|
|
90
|
-
|
|
91
|
-
function onScroll(e: Event) {
|
|
92
|
-
const target = e.currentTarget as HTMLElement
|
|
93
|
-
console.log('scroll:', target.scrollTop)
|
|
94
|
-
}
|
|
95
|
-
</script>
|
|
96
|
-
|
|
97
|
-
<template>
|
|
98
|
-
<div style="height: 200vh">
|
|
99
|
-
<h2>Basic</h2>
|
|
100
|
-
<div style="margin-bottom: 16px">
|
|
101
|
-
<button type="button" style="margin: 4px" @click="scrollToShowBar">
|
|
102
|
-
Show scroll bar
|
|
103
|
-
</button>
|
|
104
|
-
<button type="button" style="margin: 4px" @click="scrollTo100px">
|
|
105
|
-
Scroll To 100px
|
|
106
|
-
</button>
|
|
107
|
-
<button type="button" style="margin: 4px" @click="scrollToLarge">
|
|
108
|
-
Scroll To 99999999 (top)
|
|
109
|
-
</button>
|
|
110
|
-
<button type="button" style="margin: 4px" @click="scrollTo50Top">
|
|
111
|
-
Scroll To 50 (top)
|
|
112
|
-
</button>
|
|
113
|
-
<button type="button" style="margin: 4px" @click="scrollTo50Bottom">
|
|
114
|
-
Scroll To 50 (bottom)
|
|
115
|
-
</button>
|
|
116
|
-
<button type="button" style="margin: 4px" @click="scrollTo50Auto">
|
|
117
|
-
Scroll To 50 (auto)
|
|
118
|
-
</button>
|
|
119
|
-
<br>
|
|
120
|
-
<button type="button" style="margin: 4px" @click="scrollTo50TopOffset">
|
|
121
|
-
Scroll To 50 (top) + 15 offset
|
|
122
|
-
</button>
|
|
123
|
-
<button type="button" style="margin: 4px" @click="scrollTo50BottomOffset">
|
|
124
|
-
Scroll To 50 (bottom) + 15 offset
|
|
125
|
-
</button>
|
|
126
|
-
<button type="button" style="margin: 4px" @click="scrollToKey50">
|
|
127
|
-
Scroll To key 50 (auto)
|
|
128
|
-
</button>
|
|
129
|
-
<button type="button" style="margin: 4px" @click="scrollToLast">
|
|
130
|
-
Scroll To Last (top)
|
|
131
|
-
</button>
|
|
132
|
-
<button type="button" style="margin: 4px" @click="scrollToFirst">
|
|
133
|
-
Scroll To First (bottom)
|
|
134
|
-
</button>
|
|
135
|
-
<button type="button" style="margin: 4px" @click="visible = !visible">
|
|
136
|
-
Toggle visible
|
|
137
|
-
</button>
|
|
138
|
-
</div>
|
|
139
|
-
|
|
140
|
-
<VirtualList
|
|
141
|
-
ref="listRef"
|
|
142
|
-
:data="data"
|
|
143
|
-
:height="200"
|
|
144
|
-
:item-height="20"
|
|
145
|
-
item-key="id"
|
|
146
|
-
:style="{
|
|
147
|
-
border: '1px solid red',
|
|
148
|
-
boxSizing: 'border-box',
|
|
149
|
-
display: visible ? '' : 'none',
|
|
150
|
-
}"
|
|
151
|
-
@scroll="onScroll"
|
|
152
|
-
>
|
|
153
|
-
<template #default="{ item }">
|
|
154
|
-
<span
|
|
155
|
-
:style="{
|
|
156
|
-
height: `${30 + (item.id % 2 ? 0 : 10)}px`,
|
|
157
|
-
lineHeight: '30px',
|
|
158
|
-
display: 'inline-block',
|
|
159
|
-
padding: '0 8px',
|
|
160
|
-
}"
|
|
161
|
-
@click="() => console.log('Click:', item.id)"
|
|
162
|
-
>
|
|
163
|
-
{{ item.id }}
|
|
164
|
-
</span>
|
|
165
|
-
</template>
|
|
166
|
-
</VirtualList>
|
|
167
|
-
</div>
|
|
168
|
-
</template>
|
|
169
|
-
|
|
170
|
-
<style scoped>
|
|
171
|
-
button {
|
|
172
|
-
padding: 4px 8px;
|
|
173
|
-
cursor: pointer;
|
|
174
|
-
}
|
|
175
|
-
</style>
|
package/docs/height.vue
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import VirtualList from '../src'
|
|
3
|
-
|
|
4
|
-
interface Item {
|
|
5
|
-
id: number
|
|
6
|
-
height: number
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const data: Item[] = []
|
|
10
|
-
for (let i = 0; i < 100; i += 1) {
|
|
11
|
-
data.push({
|
|
12
|
-
id: i,
|
|
13
|
-
height: 30 + (i % 2 ? 70 : 0),
|
|
14
|
-
})
|
|
15
|
-
}
|
|
16
|
-
</script>
|
|
17
|
-
|
|
18
|
-
<template>
|
|
19
|
-
<div>
|
|
20
|
-
<h2>Dynamic Height</h2>
|
|
21
|
-
|
|
22
|
-
<VirtualList
|
|
23
|
-
:data="data"
|
|
24
|
-
:height="500"
|
|
25
|
-
:item-height="30"
|
|
26
|
-
item-key="id"
|
|
27
|
-
:style="{
|
|
28
|
-
border: '1px solid red',
|
|
29
|
-
boxSizing: 'border-box',
|
|
30
|
-
}"
|
|
31
|
-
>
|
|
32
|
-
<template #default="{ item }">
|
|
33
|
-
<span
|
|
34
|
-
:style="{
|
|
35
|
-
border: '1px solid gray',
|
|
36
|
-
padding: '0 16px',
|
|
37
|
-
height: `${item.height}px`,
|
|
38
|
-
lineHeight: '30px',
|
|
39
|
-
boxSizing: 'border-box',
|
|
40
|
-
display: 'inline-block',
|
|
41
|
-
}"
|
|
42
|
-
>
|
|
43
|
-
{{ item.id }}
|
|
44
|
-
</span>
|
|
45
|
-
</template>
|
|
46
|
-
</VirtualList>
|
|
47
|
-
</div>
|
|
48
|
-
</template>
|
package/docs/nest.vue
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import VirtualList from '../src'
|
|
3
|
-
|
|
4
|
-
interface Item {
|
|
5
|
-
id: number
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const data: Item[] = []
|
|
9
|
-
for (let i = 0; i < 100; i += 1) {
|
|
10
|
-
data.push({ id: i })
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function onScroll(e: Event) {
|
|
14
|
-
// console.log('scroll:', (e.currentTarget as HTMLElement).scrollTop)
|
|
15
|
-
}
|
|
16
|
-
</script>
|
|
17
|
-
|
|
18
|
-
<template>
|
|
19
|
-
<div>
|
|
20
|
-
<h2>Nested List</h2>
|
|
21
|
-
<VirtualList
|
|
22
|
-
:data="data"
|
|
23
|
-
:height="800"
|
|
24
|
-
:item-height="20"
|
|
25
|
-
item-key="id"
|
|
26
|
-
:style="{
|
|
27
|
-
border: '1px solid red',
|
|
28
|
-
boxSizing: 'border-box',
|
|
29
|
-
}"
|
|
30
|
-
@scroll="onScroll"
|
|
31
|
-
>
|
|
32
|
-
<template #default="{ item }">
|
|
33
|
-
<div :style="{ padding: '20px', background: 'yellow' }">
|
|
34
|
-
<VirtualList
|
|
35
|
-
:data="data"
|
|
36
|
-
:height="200"
|
|
37
|
-
:item-height="20"
|
|
38
|
-
item-key="id"
|
|
39
|
-
:style="{
|
|
40
|
-
border: '1px solid blue',
|
|
41
|
-
boxSizing: 'border-box',
|
|
42
|
-
background: 'white',
|
|
43
|
-
}"
|
|
44
|
-
>
|
|
45
|
-
<template #default="{ item: innerItem, index }">
|
|
46
|
-
<div
|
|
47
|
-
:style="{
|
|
48
|
-
height: '20px',
|
|
49
|
-
border: '1px solid cyan',
|
|
50
|
-
}"
|
|
51
|
-
>
|
|
52
|
-
{{ item.id }}-{{ index }}
|
|
53
|
-
</div>
|
|
54
|
-
</template>
|
|
55
|
-
</VirtualList>
|
|
56
|
-
</div>
|
|
57
|
-
</template>
|
|
58
|
-
</VirtualList>
|
|
59
|
-
</div>
|
|
60
|
-
</template>
|
package/docs/no-virtual.vue
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import VirtualList from '../src'
|
|
3
|
-
|
|
4
|
-
interface Item {
|
|
5
|
-
id: number
|
|
6
|
-
height: number
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const data: Item[] = []
|
|
10
|
-
for (let i = 0; i < 100; i += 1) {
|
|
11
|
-
data.push({
|
|
12
|
-
id: i,
|
|
13
|
-
height: 30 + (i % 2 ? 20 : 0),
|
|
14
|
-
})
|
|
15
|
-
}
|
|
16
|
-
</script>
|
|
17
|
-
|
|
18
|
-
<template>
|
|
19
|
-
<div>
|
|
20
|
-
<h2>Not Data</h2>
|
|
21
|
-
<VirtualList
|
|
22
|
-
:data="null"
|
|
23
|
-
:item-height="30"
|
|
24
|
-
:height="100"
|
|
25
|
-
item-key="id"
|
|
26
|
-
:style="{
|
|
27
|
-
border: '1px solid red',
|
|
28
|
-
boxSizing: 'border-box',
|
|
29
|
-
}"
|
|
30
|
-
>
|
|
31
|
-
<template #default="{ item }">
|
|
32
|
-
<span
|
|
33
|
-
:style="{
|
|
34
|
-
border: '1px solid gray',
|
|
35
|
-
padding: '0 16px',
|
|
36
|
-
height: `${item.height}px`,
|
|
37
|
-
lineHeight: '30px',
|
|
38
|
-
boxSizing: 'border-box',
|
|
39
|
-
display: 'inline-block',
|
|
40
|
-
}"
|
|
41
|
-
>
|
|
42
|
-
{{ item.id }}
|
|
43
|
-
</span>
|
|
44
|
-
</template>
|
|
45
|
-
</VirtualList>
|
|
46
|
-
|
|
47
|
-
<h2>Less Count</h2>
|
|
48
|
-
<VirtualList
|
|
49
|
-
:data="data.slice(0, 1)"
|
|
50
|
-
:item-height="30"
|
|
51
|
-
:height="100"
|
|
52
|
-
item-key="id"
|
|
53
|
-
:style="{
|
|
54
|
-
border: '1px solid red',
|
|
55
|
-
boxSizing: 'border-box',
|
|
56
|
-
}"
|
|
57
|
-
>
|
|
58
|
-
<template #default="{ item }">
|
|
59
|
-
<span
|
|
60
|
-
:style="{
|
|
61
|
-
border: '1px solid gray',
|
|
62
|
-
padding: '0 16px',
|
|
63
|
-
height: `${item.height}px`,
|
|
64
|
-
lineHeight: '30px',
|
|
65
|
-
boxSizing: 'border-box',
|
|
66
|
-
display: 'inline-block',
|
|
67
|
-
}"
|
|
68
|
-
>
|
|
69
|
-
{{ item.id }}
|
|
70
|
-
</span>
|
|
71
|
-
</template>
|
|
72
|
-
</VirtualList>
|
|
73
|
-
|
|
74
|
-
<h2>Less Item Height</h2>
|
|
75
|
-
<VirtualList
|
|
76
|
-
:data="data.slice(0, 10)"
|
|
77
|
-
:item-height="1"
|
|
78
|
-
:height="100"
|
|
79
|
-
item-key="id"
|
|
80
|
-
:style="{
|
|
81
|
-
border: '1px solid red',
|
|
82
|
-
boxSizing: 'border-box',
|
|
83
|
-
}"
|
|
84
|
-
>
|
|
85
|
-
<template #default="{ item }">
|
|
86
|
-
<span
|
|
87
|
-
:style="{
|
|
88
|
-
border: '1px solid gray',
|
|
89
|
-
padding: '0 16px',
|
|
90
|
-
height: `${item.height}px`,
|
|
91
|
-
lineHeight: '30px',
|
|
92
|
-
boxSizing: 'border-box',
|
|
93
|
-
display: 'inline-block',
|
|
94
|
-
}"
|
|
95
|
-
>
|
|
96
|
-
{{ item.id }}
|
|
97
|
-
</span>
|
|
98
|
-
</template>
|
|
99
|
-
</VirtualList>
|
|
100
|
-
|
|
101
|
-
<h2>Without Height</h2>
|
|
102
|
-
<VirtualList
|
|
103
|
-
:data="data"
|
|
104
|
-
:item-height="30"
|
|
105
|
-
item-key="id"
|
|
106
|
-
:style="{
|
|
107
|
-
border: '1px solid red',
|
|
108
|
-
boxSizing: 'border-box',
|
|
109
|
-
}"
|
|
110
|
-
>
|
|
111
|
-
<template #default="{ item }">
|
|
112
|
-
<span
|
|
113
|
-
:style="{
|
|
114
|
-
border: '1px solid gray',
|
|
115
|
-
padding: '0 16px',
|
|
116
|
-
height: `${item.height}px`,
|
|
117
|
-
lineHeight: '30px',
|
|
118
|
-
boxSizing: 'border-box',
|
|
119
|
-
display: 'inline-block',
|
|
120
|
-
}"
|
|
121
|
-
>
|
|
122
|
-
{{ item.id }}
|
|
123
|
-
</span>
|
|
124
|
-
</template>
|
|
125
|
-
</VirtualList>
|
|
126
|
-
</div>
|
|
127
|
-
</template>
|
package/docs/switch.vue
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ref } from 'vue'
|
|
3
|
-
import VirtualList, { type ListRef } from '../src'
|
|
4
|
-
|
|
5
|
-
interface Item {
|
|
6
|
-
id: number
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function getData(count: number): Item[] {
|
|
10
|
-
const result: Item[] = []
|
|
11
|
-
for (let i = 0; i < count; i += 1) {
|
|
12
|
-
result.push({ id: i })
|
|
13
|
-
}
|
|
14
|
-
return result
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const height = ref(200)
|
|
18
|
-
const data = ref(getData(20))
|
|
19
|
-
const fullHeight = ref(true)
|
|
20
|
-
const listRef = ref<ListRef>()
|
|
21
|
-
|
|
22
|
-
function setDataCount(count: number) {
|
|
23
|
-
data.value = getData(count)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function showScrollbar() {
|
|
27
|
-
listRef.value?.scrollTo(null)
|
|
28
|
-
}
|
|
29
|
-
</script>
|
|
30
|
-
|
|
31
|
-
<template>
|
|
32
|
-
<div style="height: 150vh">
|
|
33
|
-
<h2>Switch</h2>
|
|
34
|
-
<div style="margin-bottom: 16px">
|
|
35
|
-
<span>
|
|
36
|
-
Data:
|
|
37
|
-
<label><input type="radio" name="data" value="0" @change="() => setDataCount(0)"> 0</label>
|
|
38
|
-
<label><input type="radio" name="data" value="2" @change="() => setDataCount(2)"> 2</label>
|
|
39
|
-
<label><input type="radio" name="data" value="20" checked @change="() => setDataCount(20)"> 20</label>
|
|
40
|
-
<label><input type="radio" name="data" value="100" @change="() => setDataCount(100)"> 100</label>
|
|
41
|
-
<label><input type="radio" name="data" value="200" @change="() => setDataCount(200)"> 200</label>
|
|
42
|
-
<label><input type="radio" name="data" value="1000" @change="() => setDataCount(1000)"> 1000</label>
|
|
43
|
-
<button type="button" @click="showScrollbar">
|
|
44
|
-
Show scrollbar
|
|
45
|
-
</button>
|
|
46
|
-
</span>
|
|
47
|
-
<br>
|
|
48
|
-
<span>
|
|
49
|
-
Height:
|
|
50
|
-
<label><input type="radio" name="height" value="0" @change="() => height = 0"> 0</label>
|
|
51
|
-
<label><input type="radio" name="height" value="100" @change="() => height = 100"> 100</label>
|
|
52
|
-
<label><input type="radio" name="height" value="200" checked @change="() => height = 200"> 200</label>
|
|
53
|
-
</span>
|
|
54
|
-
<span style="margin-left: 16px">
|
|
55
|
-
<button @click="fullHeight = !fullHeight">
|
|
56
|
-
Full Height: {{ fullHeight }}
|
|
57
|
-
</button>
|
|
58
|
-
</span>
|
|
59
|
-
</div>
|
|
60
|
-
|
|
61
|
-
<VirtualList
|
|
62
|
-
ref="listRef"
|
|
63
|
-
:data="data"
|
|
64
|
-
:height="height"
|
|
65
|
-
:item-height="10"
|
|
66
|
-
item-key="id"
|
|
67
|
-
:full-height="fullHeight"
|
|
68
|
-
:style="{
|
|
69
|
-
border: '1px solid red',
|
|
70
|
-
boxSizing: 'border-box',
|
|
71
|
-
}"
|
|
72
|
-
>
|
|
73
|
-
<template #default="{ item }">
|
|
74
|
-
<span
|
|
75
|
-
:style="{
|
|
76
|
-
border: '1px solid gray',
|
|
77
|
-
padding: '0 16px',
|
|
78
|
-
height: '30px',
|
|
79
|
-
lineHeight: '30px',
|
|
80
|
-
boxSizing: 'border-box',
|
|
81
|
-
display: 'inline-block',
|
|
82
|
-
}"
|
|
83
|
-
>
|
|
84
|
-
{{ item.id }}
|
|
85
|
-
</span>
|
|
86
|
-
</template>
|
|
87
|
-
</VirtualList>
|
|
88
|
-
</div>
|
|
89
|
-
</template>
|
|
90
|
-
|
|
91
|
-
<style scoped>
|
|
92
|
-
label {
|
|
93
|
-
margin-left: 8px;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
button {
|
|
97
|
-
margin-left: 8px;
|
|
98
|
-
padding: 4px 8px;
|
|
99
|
-
cursor: pointer;
|
|
100
|
-
}
|
|
101
|
-
</style>
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import Basic from './basic.vue'
|
|
3
|
-
import Height from './height.vue'
|
|
4
|
-
import Nest from './nest.vue'
|
|
5
|
-
import NoVirtual from './no-virtual.vue'
|
|
6
|
-
import Switch from './switch.vue'
|
|
7
|
-
</script>
|
|
8
|
-
|
|
9
|
-
<template>
|
|
10
|
-
<Story title="Virtual List">
|
|
11
|
-
<Variant title="Basic">
|
|
12
|
-
<Basic />
|
|
13
|
-
</Variant>
|
|
14
|
-
|
|
15
|
-
<Variant title="Dynamic Height">
|
|
16
|
-
<Height />
|
|
17
|
-
</Variant>
|
|
18
|
-
|
|
19
|
-
<Variant title="No Virtual">
|
|
20
|
-
<NoVirtual />
|
|
21
|
-
</Variant>
|
|
22
|
-
|
|
23
|
-
<Variant title="Switch Data">
|
|
24
|
-
<Switch />
|
|
25
|
-
</Variant>
|
|
26
|
-
|
|
27
|
-
<Variant title="Nested">
|
|
28
|
-
<Nest />
|
|
29
|
-
</Variant>
|
|
30
|
-
</Story>
|
|
31
|
-
</template>
|
package/src/Filler.tsx
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import ResizeObserver from '@v-c/resize-observer'
|
|
2
|
-
import { type CSSProperties, defineComponent, type PropType, type VNode } from 'vue'
|
|
3
|
-
|
|
4
|
-
export interface InnerProps {
|
|
5
|
-
role?: string
|
|
6
|
-
id?: string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export default defineComponent({
|
|
10
|
-
name: 'Filler',
|
|
11
|
-
props: {
|
|
12
|
-
prefixCls: String,
|
|
13
|
-
/** Virtual filler height. Should be `count * itemMinHeight` */
|
|
14
|
-
height: Number,
|
|
15
|
-
/** Set offset of visible items. Should be the top of start item position */
|
|
16
|
-
offsetY: Number,
|
|
17
|
-
offsetX: Number,
|
|
18
|
-
scrollWidth: Number,
|
|
19
|
-
onInnerResize: Function as PropType<() => void>,
|
|
20
|
-
innerProps: Object as PropType<InnerProps>,
|
|
21
|
-
rtl: Boolean,
|
|
22
|
-
extra: Object as PropType<VNode>,
|
|
23
|
-
},
|
|
24
|
-
setup(props, { slots }) {
|
|
25
|
-
return () => {
|
|
26
|
-
let outerStyle: CSSProperties = {}
|
|
27
|
-
let innerStyle: CSSProperties = {
|
|
28
|
-
display: 'flex',
|
|
29
|
-
flexDirection: 'column',
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (props.offsetY !== undefined) {
|
|
33
|
-
outerStyle = {
|
|
34
|
-
height: `${props.height}px`,
|
|
35
|
-
position: 'relative',
|
|
36
|
-
overflow: 'hidden',
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
innerStyle = {
|
|
40
|
-
...innerStyle,
|
|
41
|
-
transform: `translateY(${props.offsetY}px)`,
|
|
42
|
-
[props.rtl ? 'marginRight' : 'marginLeft']: `-${props.offsetX || 0}px`,
|
|
43
|
-
position: 'absolute',
|
|
44
|
-
left: 0,
|
|
45
|
-
right: 0,
|
|
46
|
-
top: 0,
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return (
|
|
51
|
-
<div style={outerStyle}>
|
|
52
|
-
<ResizeObserver
|
|
53
|
-
onResize={({ offsetHeight }) => {
|
|
54
|
-
if (offsetHeight && props.onInnerResize) {
|
|
55
|
-
props.onInnerResize()
|
|
56
|
-
}
|
|
57
|
-
}}
|
|
58
|
-
>
|
|
59
|
-
<div
|
|
60
|
-
style={innerStyle}
|
|
61
|
-
class={props.prefixCls ? `${props.prefixCls}-holder-inner` : undefined}
|
|
62
|
-
{...props.innerProps}
|
|
63
|
-
>
|
|
64
|
-
{slots.default?.()}
|
|
65
|
-
{props.extra}
|
|
66
|
-
</div>
|
|
67
|
-
</ResizeObserver>
|
|
68
|
-
</div>
|
|
69
|
-
)
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
})
|
package/src/Item.tsx
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { filterEmpty } from '@v-c/util/dist/props-util'
|
|
2
|
-
import { cloneVNode, defineComponent, type PropType, shallowRef } from 'vue'
|
|
3
|
-
|
|
4
|
-
export interface ItemProps {
|
|
5
|
-
setRef: (element: HTMLElement | null) => void
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export default defineComponent({
|
|
9
|
-
name: 'Item',
|
|
10
|
-
props: {
|
|
11
|
-
setRef: {
|
|
12
|
-
type: Function as PropType<(element: HTMLElement | null) => void>,
|
|
13
|
-
required: true,
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
setup(props, { slots }) {
|
|
17
|
-
// Store the ref callback to avoid recreating it on each render
|
|
18
|
-
const currentElement = shallowRef<HTMLElement | null>(null)
|
|
19
|
-
const refFunc = (node: any) => {
|
|
20
|
-
if (currentElement.value !== node) {
|
|
21
|
-
currentElement.value = node
|
|
22
|
-
props.setRef(node)
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return () => {
|
|
27
|
-
const child = filterEmpty(slots.default?.() ?? [])[0]
|
|
28
|
-
if (!child)
|
|
29
|
-
return null
|
|
30
|
-
|
|
31
|
-
return cloneVNode(child, { ref: refFunc })
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
})
|