@v-c/virtual-list 1.0.0 → 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/List.cjs +10 -6
- package/dist/List.js +11 -7
- package/dist/hooks/useHeights.cjs +1 -1
- package/dist/hooks/useHeights.js +2 -2
- package/package.json +6 -2
- package/bump.config.ts +0 -6
- package/docs/animate.less +0 -31
- package/docs/animate.vue +0 -159
- package/docs/basic.vue +0 -176
- package/docs/height.vue +0 -48
- package/docs/nest.vue +0 -60
- package/docs/no-virtual.vue +0 -127
- package/docs/switch.vue +0 -102
- package/docs/virtual-list.stories.vue +0 -35
- package/src/Filler.tsx +0 -73
- package/src/Item.tsx +0 -35
- package/src/List.tsx +0 -642
- package/src/ScrollBar.tsx +0 -287
- package/src/__tests__/List.test.ts +0 -59
- package/src/hooks/useDiffItem.ts +0 -28
- package/src/hooks/useFrameWheel.ts +0 -142
- package/src/hooks/useGetSize.ts +0 -45
- package/src/hooks/useHeights.ts +0 -107
- package/src/hooks/useMobileTouchMove.ts +0 -132
- package/src/hooks/useOriginScroll.ts +0 -48
- package/src/hooks/useScrollDrag.ts +0 -124
- package/src/hooks/useScrollTo.tsx +0 -184
- 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/tsconfig.json +0 -7
- package/vite.config.ts +0 -18
- package/vitest.config.ts +0 -11
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,102 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import type { ListRef } from '../src'
|
|
3
|
-
import { ref } from 'vue'
|
|
4
|
-
import VirtualList from '../src'
|
|
5
|
-
|
|
6
|
-
interface Item {
|
|
7
|
-
id: number
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function getData(count: number): Item[] {
|
|
11
|
-
const result: Item[] = []
|
|
12
|
-
for (let i = 0; i < count; i += 1) {
|
|
13
|
-
result.push({ id: i })
|
|
14
|
-
}
|
|
15
|
-
return result
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const height = ref(200)
|
|
19
|
-
const data = ref(getData(20))
|
|
20
|
-
const fullHeight = ref(true)
|
|
21
|
-
const listRef = ref<ListRef>()
|
|
22
|
-
|
|
23
|
-
function setDataCount(count: number) {
|
|
24
|
-
data.value = getData(count)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function showScrollbar() {
|
|
28
|
-
listRef.value?.scrollTo(null)
|
|
29
|
-
}
|
|
30
|
-
</script>
|
|
31
|
-
|
|
32
|
-
<template>
|
|
33
|
-
<div style="height: 150vh">
|
|
34
|
-
<h2>Switch</h2>
|
|
35
|
-
<div style="margin-bottom: 16px">
|
|
36
|
-
<span>
|
|
37
|
-
Data:
|
|
38
|
-
<label><input type="radio" name="data" value="0" @change="() => setDataCount(0)"> 0</label>
|
|
39
|
-
<label><input type="radio" name="data" value="2" @change="() => setDataCount(2)"> 2</label>
|
|
40
|
-
<label><input type="radio" name="data" value="20" checked @change="() => setDataCount(20)"> 20</label>
|
|
41
|
-
<label><input type="radio" name="data" value="100" @change="() => setDataCount(100)"> 100</label>
|
|
42
|
-
<label><input type="radio" name="data" value="200" @change="() => setDataCount(200)"> 200</label>
|
|
43
|
-
<label><input type="radio" name="data" value="1000" @change="() => setDataCount(1000)"> 1000</label>
|
|
44
|
-
<button type="button" @click="showScrollbar">
|
|
45
|
-
Show scrollbar
|
|
46
|
-
</button>
|
|
47
|
-
</span>
|
|
48
|
-
<br>
|
|
49
|
-
<span>
|
|
50
|
-
Height:
|
|
51
|
-
<label><input type="radio" name="height" value="0" @change="() => height = 0"> 0</label>
|
|
52
|
-
<label><input type="radio" name="height" value="100" @change="() => height = 100"> 100</label>
|
|
53
|
-
<label><input type="radio" name="height" value="200" checked @change="() => height = 200"> 200</label>
|
|
54
|
-
</span>
|
|
55
|
-
<span style="margin-left: 16px">
|
|
56
|
-
<button @click="fullHeight = !fullHeight">
|
|
57
|
-
Full Height: {{ fullHeight }}
|
|
58
|
-
</button>
|
|
59
|
-
</span>
|
|
60
|
-
</div>
|
|
61
|
-
|
|
62
|
-
<VirtualList
|
|
63
|
-
ref="listRef"
|
|
64
|
-
:data="data"
|
|
65
|
-
:height="height"
|
|
66
|
-
:item-height="10"
|
|
67
|
-
item-key="id"
|
|
68
|
-
:full-height="fullHeight"
|
|
69
|
-
:style="{
|
|
70
|
-
border: '1px solid red',
|
|
71
|
-
boxSizing: 'border-box',
|
|
72
|
-
}"
|
|
73
|
-
>
|
|
74
|
-
<template #default="{ item }">
|
|
75
|
-
<span
|
|
76
|
-
:style="{
|
|
77
|
-
border: '1px solid gray',
|
|
78
|
-
padding: '0 16px',
|
|
79
|
-
height: '30px',
|
|
80
|
-
lineHeight: '30px',
|
|
81
|
-
boxSizing: 'border-box',
|
|
82
|
-
display: 'inline-block',
|
|
83
|
-
}"
|
|
84
|
-
>
|
|
85
|
-
{{ item.id }}
|
|
86
|
-
</span>
|
|
87
|
-
</template>
|
|
88
|
-
</VirtualList>
|
|
89
|
-
</div>
|
|
90
|
-
</template>
|
|
91
|
-
|
|
92
|
-
<style scoped>
|
|
93
|
-
label {
|
|
94
|
-
margin-left: 8px;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
button {
|
|
98
|
-
margin-left: 8px;
|
|
99
|
-
padding: 4px 8px;
|
|
100
|
-
cursor: pointer;
|
|
101
|
-
}
|
|
102
|
-
</style>
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import Animate from './animate.vue'
|
|
3
|
-
import Basic from './basic.vue'
|
|
4
|
-
import Height from './height.vue'
|
|
5
|
-
import Nest from './nest.vue'
|
|
6
|
-
import NoVirtual from './no-virtual.vue'
|
|
7
|
-
import Switch from './switch.vue'
|
|
8
|
-
</script>
|
|
9
|
-
|
|
10
|
-
<template>
|
|
11
|
-
<Story title="Virtual List">
|
|
12
|
-
<Variant title="Basic">
|
|
13
|
-
<Basic />
|
|
14
|
-
</Variant>
|
|
15
|
-
<Variant title="Animate">
|
|
16
|
-
<Animate />
|
|
17
|
-
</Variant>
|
|
18
|
-
|
|
19
|
-
<Variant title="Dynamic Height">
|
|
20
|
-
<Height />
|
|
21
|
-
</Variant>
|
|
22
|
-
|
|
23
|
-
<Variant title="No Virtual">
|
|
24
|
-
<NoVirtual />
|
|
25
|
-
</Variant>
|
|
26
|
-
|
|
27
|
-
<Variant title="Switch Data">
|
|
28
|
-
<Switch />
|
|
29
|
-
</Variant>
|
|
30
|
-
|
|
31
|
-
<Variant title="Nested">
|
|
32
|
-
<Nest />
|
|
33
|
-
</Variant>
|
|
34
|
-
</Story>
|
|
35
|
-
</template>
|
package/src/Filler.tsx
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import type { CSSProperties, PropType, VNode } from 'vue'
|
|
2
|
-
import ResizeObserver from '@v-c/resize-observer'
|
|
3
|
-
import { defineComponent } from 'vue'
|
|
4
|
-
|
|
5
|
-
export interface InnerProps {
|
|
6
|
-
role?: string
|
|
7
|
-
id?: string
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export default defineComponent({
|
|
11
|
-
name: 'Filler',
|
|
12
|
-
props: {
|
|
13
|
-
prefixCls: String,
|
|
14
|
-
/** Virtual filler height. Should be `count * itemMinHeight` */
|
|
15
|
-
height: Number,
|
|
16
|
-
/** Set offset of visible items. Should be the top of start item position */
|
|
17
|
-
offsetY: Number,
|
|
18
|
-
offsetX: Number,
|
|
19
|
-
scrollWidth: Number,
|
|
20
|
-
onInnerResize: Function as PropType<() => void>,
|
|
21
|
-
innerProps: Object as PropType<InnerProps>,
|
|
22
|
-
rtl: Boolean,
|
|
23
|
-
extra: Object as PropType<VNode>,
|
|
24
|
-
},
|
|
25
|
-
setup(props, { slots }) {
|
|
26
|
-
return () => {
|
|
27
|
-
let outerStyle: CSSProperties = {}
|
|
28
|
-
let innerStyle: CSSProperties = {
|
|
29
|
-
display: 'flex',
|
|
30
|
-
flexDirection: 'column',
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (props.offsetY !== undefined) {
|
|
34
|
-
outerStyle = {
|
|
35
|
-
height: `${props.height}px`,
|
|
36
|
-
position: 'relative',
|
|
37
|
-
overflow: 'hidden',
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
innerStyle = {
|
|
41
|
-
...innerStyle,
|
|
42
|
-
transform: `translateY(${props.offsetY}px)`,
|
|
43
|
-
[props.rtl ? 'marginRight' : 'marginLeft']: `-${props.offsetX || 0}px`,
|
|
44
|
-
position: 'absolute',
|
|
45
|
-
left: 0,
|
|
46
|
-
right: 0,
|
|
47
|
-
top: 0,
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
<div style={outerStyle}>
|
|
53
|
-
<ResizeObserver
|
|
54
|
-
onResize={({ offsetHeight }) => {
|
|
55
|
-
if (offsetHeight && props.onInnerResize) {
|
|
56
|
-
props.onInnerResize()
|
|
57
|
-
}
|
|
58
|
-
}}
|
|
59
|
-
>
|
|
60
|
-
<div
|
|
61
|
-
style={innerStyle}
|
|
62
|
-
class={props.prefixCls ? `${props.prefixCls}-holder-inner` : undefined}
|
|
63
|
-
{...props.innerProps}
|
|
64
|
-
>
|
|
65
|
-
{slots.default?.()}
|
|
66
|
-
{props.extra}
|
|
67
|
-
</div>
|
|
68
|
-
</ResizeObserver>
|
|
69
|
-
</div>
|
|
70
|
-
)
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
})
|
package/src/Item.tsx
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { PropType } from 'vue'
|
|
2
|
-
import { filterEmpty } from '@v-c/util/dist/props-util'
|
|
3
|
-
import { cloneVNode, defineComponent, shallowRef } from 'vue'
|
|
4
|
-
|
|
5
|
-
export interface ItemProps {
|
|
6
|
-
setRef: (element: HTMLElement | null) => void
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export default defineComponent({
|
|
10
|
-
name: 'Item',
|
|
11
|
-
props: {
|
|
12
|
-
setRef: {
|
|
13
|
-
type: Function as PropType<(element: HTMLElement | null) => void>,
|
|
14
|
-
required: true,
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
setup(props, { slots }) {
|
|
18
|
-
// Store the ref callback to avoid recreating it on each render
|
|
19
|
-
const currentElement = shallowRef<HTMLElement | null>(null)
|
|
20
|
-
const refFunc = (node: any) => {
|
|
21
|
-
if (currentElement.value !== node) {
|
|
22
|
-
currentElement.value = node
|
|
23
|
-
props.setRef(node)
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return () => {
|
|
28
|
-
const child = filterEmpty(slots.default?.() ?? [])[0]
|
|
29
|
-
if (!child)
|
|
30
|
-
return null
|
|
31
|
-
|
|
32
|
-
return cloneVNode(child, { ref: refFunc })
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
})
|