@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/dist/List.cjs
CHANGED
|
@@ -69,9 +69,12 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
69
69
|
inheritAttrs: false,
|
|
70
70
|
setup(props, { expose, attrs, slots }) {
|
|
71
71
|
const itemHeight = (0, vue.computed)(() => props.itemHeight);
|
|
72
|
+
const itemKey = (0, vue.toRef)(props, "itemKey");
|
|
72
73
|
const getKey = (item) => {
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
item = (0, vue.toRaw)(item);
|
|
75
|
+
const _itemKey = itemKey.value;
|
|
76
|
+
if (typeof _itemKey === "function") return _itemKey(item);
|
|
77
|
+
return item?.[_itemKey];
|
|
75
78
|
};
|
|
76
79
|
const [setInstanceRef, collectHeight, heights, heightUpdatedMark] = require_useHeights.default(getKey, void 0, void 0);
|
|
77
80
|
const mergedData = (0, vue.computed)(() => props.data || EMPTY_DATA);
|
|
@@ -121,6 +124,7 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
121
124
|
fillerOffset.value = void 0;
|
|
122
125
|
return;
|
|
123
126
|
}
|
|
127
|
+
const { itemHeight: itemHeight$1, height } = props;
|
|
124
128
|
if (!inVirtual.value) {
|
|
125
129
|
scrollHeight.value = fillerInnerRef.value?.offsetHeight || 0;
|
|
126
130
|
start.value = 0;
|
|
@@ -133,23 +137,23 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
133
137
|
let startOffset;
|
|
134
138
|
let endIndex;
|
|
135
139
|
const dataLen = mergedData.value.length;
|
|
136
|
-
const data = mergedData.value;
|
|
140
|
+
const data = (0, vue.toRaw)(mergedData.value);
|
|
137
141
|
for (let i = 0; i < dataLen; i += 1) {
|
|
138
142
|
const item = data[i];
|
|
139
143
|
const key = getKey(item);
|
|
140
144
|
const cacheHeight = heights.get(key);
|
|
141
|
-
const currentItemBottom = itemTop + (cacheHeight === void 0 ?
|
|
145
|
+
const currentItemBottom = itemTop + (cacheHeight === void 0 ? itemHeight$1 : cacheHeight);
|
|
142
146
|
if (currentItemBottom >= offsetTop.value && startIndex === void 0) {
|
|
143
147
|
startIndex = i;
|
|
144
148
|
startOffset = itemTop;
|
|
145
149
|
}
|
|
146
|
-
if (currentItemBottom > offsetTop.value +
|
|
150
|
+
if (currentItemBottom > offsetTop.value + height && endIndex === void 0) endIndex = i;
|
|
147
151
|
itemTop = currentItemBottom;
|
|
148
152
|
}
|
|
149
153
|
if (startIndex === void 0) {
|
|
150
154
|
startIndex = 0;
|
|
151
155
|
startOffset = 0;
|
|
152
|
-
endIndex = Math.ceil(
|
|
156
|
+
endIndex = Math.ceil(height / itemHeight$1);
|
|
153
157
|
}
|
|
154
158
|
if (endIndex === void 0) endIndex = mergedData.value.length - 1;
|
|
155
159
|
endIndex = Math.min(endIndex + 1, mergedData.value.length - 1);
|
package/dist/List.js
CHANGED
|
@@ -9,7 +9,7 @@ import useScrollDrag from "./hooks/useScrollDrag.js";
|
|
|
9
9
|
import useScrollTo from "./hooks/useScrollTo.js";
|
|
10
10
|
import ScrollBar_default from "./ScrollBar.js";
|
|
11
11
|
import { getSpinSize } from "./utils/scrollbarUtil.js";
|
|
12
|
-
import { computed, createVNode, defineComponent, isVNode, mergeProps, ref, shallowRef, watch } from "vue";
|
|
12
|
+
import { computed, createVNode, defineComponent, isVNode, mergeProps, ref, shallowRef, toRaw, toRef, watch } from "vue";
|
|
13
13
|
import ResizeObserver from "@v-c/resize-observer";
|
|
14
14
|
import { pureAttrs } from "@v-c/util/dist/props-util";
|
|
15
15
|
function _isSlot(s) {
|
|
@@ -66,9 +66,12 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
66
66
|
inheritAttrs: false,
|
|
67
67
|
setup(props, { expose, attrs, slots }) {
|
|
68
68
|
const itemHeight = computed(() => props.itemHeight);
|
|
69
|
+
const itemKey = toRef(props, "itemKey");
|
|
69
70
|
const getKey = (item) => {
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
item = toRaw(item);
|
|
72
|
+
const _itemKey = itemKey.value;
|
|
73
|
+
if (typeof _itemKey === "function") return _itemKey(item);
|
|
74
|
+
return item?.[_itemKey];
|
|
72
75
|
};
|
|
73
76
|
const [setInstanceRef, collectHeight, heights, heightUpdatedMark] = useHeights(getKey, void 0, void 0);
|
|
74
77
|
const mergedData = computed(() => props.data || EMPTY_DATA);
|
|
@@ -118,6 +121,7 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
118
121
|
fillerOffset.value = void 0;
|
|
119
122
|
return;
|
|
120
123
|
}
|
|
124
|
+
const { itemHeight: itemHeight$1, height } = props;
|
|
121
125
|
if (!inVirtual.value) {
|
|
122
126
|
scrollHeight.value = fillerInnerRef.value?.offsetHeight || 0;
|
|
123
127
|
start.value = 0;
|
|
@@ -130,23 +134,23 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
130
134
|
let startOffset;
|
|
131
135
|
let endIndex;
|
|
132
136
|
const dataLen = mergedData.value.length;
|
|
133
|
-
const data = mergedData.value;
|
|
137
|
+
const data = toRaw(mergedData.value);
|
|
134
138
|
for (let i = 0; i < dataLen; i += 1) {
|
|
135
139
|
const item = data[i];
|
|
136
140
|
const key = getKey(item);
|
|
137
141
|
const cacheHeight = heights.get(key);
|
|
138
|
-
const currentItemBottom = itemTop + (cacheHeight === void 0 ?
|
|
142
|
+
const currentItemBottom = itemTop + (cacheHeight === void 0 ? itemHeight$1 : cacheHeight);
|
|
139
143
|
if (currentItemBottom >= offsetTop.value && startIndex === void 0) {
|
|
140
144
|
startIndex = i;
|
|
141
145
|
startOffset = itemTop;
|
|
142
146
|
}
|
|
143
|
-
if (currentItemBottom > offsetTop.value +
|
|
147
|
+
if (currentItemBottom > offsetTop.value + height && endIndex === void 0) endIndex = i;
|
|
144
148
|
itemTop = currentItemBottom;
|
|
145
149
|
}
|
|
146
150
|
if (startIndex === void 0) {
|
|
147
151
|
startIndex = 0;
|
|
148
152
|
startOffset = 0;
|
|
149
|
-
endIndex = Math.ceil(
|
|
153
|
+
endIndex = Math.ceil(height / itemHeight$1);
|
|
150
154
|
}
|
|
151
155
|
if (endIndex === void 0) endIndex = mergedData.value.length - 1;
|
|
152
156
|
endIndex = Math.min(endIndex + 1, mergedData.value.length - 1);
|
|
@@ -9,7 +9,7 @@ function parseNumber(value) {
|
|
|
9
9
|
function useHeights(getKey, onItemAdd, onItemRemove) {
|
|
10
10
|
const updatedMark = (0, vue.ref)(0);
|
|
11
11
|
const instanceRef = (0, vue.ref)(/* @__PURE__ */ new Map());
|
|
12
|
-
const heightsRef =
|
|
12
|
+
const heightsRef = new require_CacheMap.default();
|
|
13
13
|
const promiseIdRef = (0, vue.ref)(0);
|
|
14
14
|
function cancelRaf() {
|
|
15
15
|
promiseIdRef.value += 1;
|
package/dist/hooks/useHeights.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import CacheMap_default from "../utils/CacheMap.js";
|
|
2
|
-
import { onUnmounted,
|
|
2
|
+
import { onUnmounted, ref } from "vue";
|
|
3
3
|
function parseNumber(value) {
|
|
4
4
|
const num = parseFloat(value);
|
|
5
5
|
return isNaN(num) ? 0 : num;
|
|
@@ -7,7 +7,7 @@ function parseNumber(value) {
|
|
|
7
7
|
function useHeights(getKey, onItemAdd, onItemRemove) {
|
|
8
8
|
const updatedMark = ref(0);
|
|
9
9
|
const instanceRef = ref(/* @__PURE__ */ new Map());
|
|
10
|
-
const heightsRef =
|
|
10
|
+
const heightsRef = new CacheMap_default();
|
|
11
11
|
const promiseIdRef = ref(0);
|
|
12
12
|
function cancelRaf() {
|
|
13
13
|
promiseIdRef.value += 1;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@v-c/virtual-list",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.1",
|
|
5
5
|
"description": "Vue Virtual List Component",
|
|
6
6
|
"author": "",
|
|
7
7
|
"license": "MIT",
|
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
"./package.json": "./package.json"
|
|
21
21
|
},
|
|
22
22
|
"main": "./dist/index.js",
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"package.json"
|
|
26
|
+
],
|
|
23
27
|
"publishConfig": {
|
|
24
28
|
"access": "public"
|
|
25
29
|
},
|
|
@@ -28,7 +32,7 @@
|
|
|
28
32
|
},
|
|
29
33
|
"dependencies": {
|
|
30
34
|
"@v-c/resize-observer": "^1.0.0",
|
|
31
|
-
"@v-c/util": "^1.0.
|
|
35
|
+
"@v-c/util": "^1.0.2"
|
|
32
36
|
},
|
|
33
37
|
"scripts": {
|
|
34
38
|
"build": "vite build",
|
package/bump.config.ts
DELETED
package/docs/animate.less
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
.motion {
|
|
2
|
-
transition: all 0.3s;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
.item {
|
|
6
|
-
display: inline-block;
|
|
7
|
-
box-sizing: border-box;
|
|
8
|
-
margin: 0;
|
|
9
|
-
padding: 0 16px;
|
|
10
|
-
overflow: hidden;
|
|
11
|
-
line-height: 31px;
|
|
12
|
-
position: relative;
|
|
13
|
-
|
|
14
|
-
&:hover {
|
|
15
|
-
background: rgba(255, 0, 0, 0.1);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
&::after {
|
|
19
|
-
content: '';
|
|
20
|
-
border-bottom: 1px solid gray;
|
|
21
|
-
position: absolute;
|
|
22
|
-
bottom: 0;
|
|
23
|
-
left: 0;
|
|
24
|
-
right: 0;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
button {
|
|
28
|
-
vertical-align: text-top;
|
|
29
|
-
margin-right: 8px;
|
|
30
|
-
}
|
|
31
|
-
}
|
package/docs/animate.vue
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import type { ListRef } from '../src'
|
|
3
|
-
import { ref } from 'vue'
|
|
4
|
-
import VirtualList from '../src'
|
|
5
|
-
import './animate.less'
|
|
6
|
-
|
|
7
|
-
interface Item {
|
|
8
|
-
id: string
|
|
9
|
-
uuid: number
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
let uuid = 0
|
|
13
|
-
function genItem(): Item {
|
|
14
|
-
const item = {
|
|
15
|
-
id: `key_${uuid}`,
|
|
16
|
-
uuid,
|
|
17
|
-
}
|
|
18
|
-
uuid += 1
|
|
19
|
-
return item
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const originData: Item[] = []
|
|
23
|
-
for (let i = 0; i < 1000; i += 1) {
|
|
24
|
-
originData.push(genItem())
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const data = ref([...originData])
|
|
28
|
-
const closeMap = ref<Record<string, boolean>>({})
|
|
29
|
-
const animating = ref(false)
|
|
30
|
-
const insertIndex = ref<number>()
|
|
31
|
-
|
|
32
|
-
const listRef = ref<ListRef>()
|
|
33
|
-
|
|
34
|
-
function onClose(id: string) {
|
|
35
|
-
closeMap.value = {
|
|
36
|
-
...closeMap.value,
|
|
37
|
-
[id]: true,
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function onLeave(id: string) {
|
|
42
|
-
data.value = data.value.filter(item => item.id !== id)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function onAppear(...args: any[]) {
|
|
46
|
-
console.log('Appear:', args)
|
|
47
|
-
animating.value = false
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function lockForAnimation() {
|
|
51
|
-
animating.value = true
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function onInsertBefore(id: string) {
|
|
55
|
-
const index = data.value.findIndex(item => item.id === id)
|
|
56
|
-
const newData = [...data.value.slice(0, index), genItem(), ...data.value.slice(index)]
|
|
57
|
-
insertIndex.value = index
|
|
58
|
-
data.value = newData
|
|
59
|
-
lockForAnimation()
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function onInsertAfter(id: string) {
|
|
63
|
-
const index = data.value.findIndex(item => item.id === id) + 1
|
|
64
|
-
const newData = [...data.value.slice(0, index), genItem(), ...data.value.slice(index)]
|
|
65
|
-
insertIndex.value = index
|
|
66
|
-
data.value = newData
|
|
67
|
-
lockForAnimation()
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function getCurrentHeight(el: Element) {
|
|
71
|
-
const node = el as HTMLElement
|
|
72
|
-
node.style.height = `${node.offsetHeight}px`
|
|
73
|
-
node.style.opacity = '1'
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function getMaxHeight(el: Element) {
|
|
77
|
-
const node = el as HTMLElement
|
|
78
|
-
node.style.height = `${node.scrollHeight}px`
|
|
79
|
-
node.style.opacity = '1'
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function getCollapsedHeight(el: Element) {
|
|
83
|
-
const node = el as HTMLElement
|
|
84
|
-
node.style.height = '0'
|
|
85
|
-
node.style.opacity = '0'
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function resetHeight(el: Element) {
|
|
89
|
-
const node = el as HTMLElement
|
|
90
|
-
node.style.height = ''
|
|
91
|
-
node.style.opacity = ''
|
|
92
|
-
onAppear()
|
|
93
|
-
}
|
|
94
|
-
</script>
|
|
95
|
-
|
|
96
|
-
<template>
|
|
97
|
-
<div>
|
|
98
|
-
<h2>Animate</h2>
|
|
99
|
-
<p>Current: {{ data.length }} records</p>
|
|
100
|
-
|
|
101
|
-
<VirtualList
|
|
102
|
-
ref="listRef"
|
|
103
|
-
:data="data"
|
|
104
|
-
data-id="list"
|
|
105
|
-
:height="200"
|
|
106
|
-
:item-height="20"
|
|
107
|
-
item-key="id"
|
|
108
|
-
:style="{
|
|
109
|
-
border: '1px solid red',
|
|
110
|
-
boxSizing: 'border-box',
|
|
111
|
-
}"
|
|
112
|
-
>
|
|
113
|
-
<template #default="{ item, index }">
|
|
114
|
-
<Transition
|
|
115
|
-
name="motion"
|
|
116
|
-
:appear="animating && insertIndex === index"
|
|
117
|
-
@before-enter="getCollapsedHeight"
|
|
118
|
-
@enter="getMaxHeight"
|
|
119
|
-
@after-enter="resetHeight"
|
|
120
|
-
@before-leave="getCurrentHeight"
|
|
121
|
-
@leave="getCollapsedHeight"
|
|
122
|
-
@after-leave="() => onLeave(item.id)"
|
|
123
|
-
>
|
|
124
|
-
<div
|
|
125
|
-
v-if="!(closeMap as any)[item.id]"
|
|
126
|
-
class="item"
|
|
127
|
-
:data-id="item.id"
|
|
128
|
-
>
|
|
129
|
-
<div :style="{ height: item.uuid % 2 ? '100px' : undefined }">
|
|
130
|
-
<button type="button" @click="onClose(item.id)">
|
|
131
|
-
Close
|
|
132
|
-
</button>
|
|
133
|
-
<button type="button" @click="onInsertBefore(item.id)">
|
|
134
|
-
Insert Before
|
|
135
|
-
</button>
|
|
136
|
-
<button type="button" @click="onInsertAfter(item.id)">
|
|
137
|
-
Insert After
|
|
138
|
-
</button>
|
|
139
|
-
{{ item.id }}
|
|
140
|
-
</div>
|
|
141
|
-
</div>
|
|
142
|
-
</Transition>
|
|
143
|
-
</template>
|
|
144
|
-
</VirtualList>
|
|
145
|
-
</div>
|
|
146
|
-
</template>
|
|
147
|
-
|
|
148
|
-
<style scoped>
|
|
149
|
-
.motion-enter-active,
|
|
150
|
-
.motion-leave-active {
|
|
151
|
-
transition: all 0.3s;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
.motion-enter-from,
|
|
155
|
-
.motion-leave-to {
|
|
156
|
-
height: 0;
|
|
157
|
-
opacity: 0;
|
|
158
|
-
}
|
|
159
|
-
</style>
|
package/docs/basic.vue
DELETED
|
@@ -1,176 +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
|
-
const data: Item[] = []
|
|
11
|
-
for (let i = 0; i < 1000; i += 1) {
|
|
12
|
-
data.push({ id: i })
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const listRef = ref<ListRef>()
|
|
16
|
-
|
|
17
|
-
function scrollToShowBar() {
|
|
18
|
-
listRef.value?.scrollTo(null)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function scrollTo100px() {
|
|
22
|
-
listRef.value?.scrollTo(500)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function scrollToLarge() {
|
|
26
|
-
listRef.value?.scrollTo({
|
|
27
|
-
index: 99999999,
|
|
28
|
-
align: 'top',
|
|
29
|
-
})
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function scrollTo50Top() {
|
|
33
|
-
listRef.value?.scrollTo({
|
|
34
|
-
index: 50,
|
|
35
|
-
align: 'top',
|
|
36
|
-
})
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function scrollTo50Bottom() {
|
|
40
|
-
listRef.value?.scrollTo({
|
|
41
|
-
index: 50,
|
|
42
|
-
align: 'bottom',
|
|
43
|
-
})
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function scrollTo50Auto() {
|
|
47
|
-
listRef.value?.scrollTo({
|
|
48
|
-
index: 50,
|
|
49
|
-
align: 'auto',
|
|
50
|
-
})
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function scrollTo50TopOffset() {
|
|
54
|
-
listRef.value?.scrollTo({
|
|
55
|
-
index: 50,
|
|
56
|
-
align: 'top',
|
|
57
|
-
offset: 15,
|
|
58
|
-
})
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function scrollTo50BottomOffset() {
|
|
62
|
-
listRef.value?.scrollTo({
|
|
63
|
-
index: 50,
|
|
64
|
-
align: 'bottom',
|
|
65
|
-
offset: 15,
|
|
66
|
-
})
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function scrollToKey50() {
|
|
70
|
-
listRef.value?.scrollTo({
|
|
71
|
-
key: 50,
|
|
72
|
-
align: 'auto',
|
|
73
|
-
})
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function scrollToLast() {
|
|
77
|
-
listRef.value?.scrollTo({
|
|
78
|
-
index: data.length - 2,
|
|
79
|
-
align: 'top',
|
|
80
|
-
})
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function scrollToFirst() {
|
|
84
|
-
listRef.value?.scrollTo({
|
|
85
|
-
index: 0,
|
|
86
|
-
align: 'bottom',
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const visible = ref(true)
|
|
91
|
-
|
|
92
|
-
function onScroll(e: Event) {
|
|
93
|
-
const target = e.currentTarget as HTMLElement
|
|
94
|
-
console.log('scroll:', target.scrollTop)
|
|
95
|
-
}
|
|
96
|
-
</script>
|
|
97
|
-
|
|
98
|
-
<template>
|
|
99
|
-
<div style="height: 200vh">
|
|
100
|
-
<h2>Basic</h2>
|
|
101
|
-
<div style="margin-bottom: 16px">
|
|
102
|
-
<button type="button" style="margin: 4px" @click="scrollToShowBar">
|
|
103
|
-
Show scroll bar
|
|
104
|
-
</button>
|
|
105
|
-
<button type="button" style="margin: 4px" @click="scrollTo100px">
|
|
106
|
-
Scroll To 100px
|
|
107
|
-
</button>
|
|
108
|
-
<button type="button" style="margin: 4px" @click="scrollToLarge">
|
|
109
|
-
Scroll To 99999999 (top)
|
|
110
|
-
</button>
|
|
111
|
-
<button type="button" style="margin: 4px" @click="scrollTo50Top">
|
|
112
|
-
Scroll To 50 (top)
|
|
113
|
-
</button>
|
|
114
|
-
<button type="button" style="margin: 4px" @click="scrollTo50Bottom">
|
|
115
|
-
Scroll To 50 (bottom)
|
|
116
|
-
</button>
|
|
117
|
-
<button type="button" style="margin: 4px" @click="scrollTo50Auto">
|
|
118
|
-
Scroll To 50 (auto)
|
|
119
|
-
</button>
|
|
120
|
-
<br>
|
|
121
|
-
<button type="button" style="margin: 4px" @click="scrollTo50TopOffset">
|
|
122
|
-
Scroll To 50 (top) + 15 offset
|
|
123
|
-
</button>
|
|
124
|
-
<button type="button" style="margin: 4px" @click="scrollTo50BottomOffset">
|
|
125
|
-
Scroll To 50 (bottom) + 15 offset
|
|
126
|
-
</button>
|
|
127
|
-
<button type="button" style="margin: 4px" @click="scrollToKey50">
|
|
128
|
-
Scroll To key 50 (auto)
|
|
129
|
-
</button>
|
|
130
|
-
<button type="button" style="margin: 4px" @click="scrollToLast">
|
|
131
|
-
Scroll To Last (top)
|
|
132
|
-
</button>
|
|
133
|
-
<button type="button" style="margin: 4px" @click="scrollToFirst">
|
|
134
|
-
Scroll To First (bottom)
|
|
135
|
-
</button>
|
|
136
|
-
<button type="button" style="margin: 4px" @click="visible = !visible">
|
|
137
|
-
Toggle visible
|
|
138
|
-
</button>
|
|
139
|
-
</div>
|
|
140
|
-
|
|
141
|
-
<VirtualList
|
|
142
|
-
ref="listRef"
|
|
143
|
-
:data="data"
|
|
144
|
-
:height="200"
|
|
145
|
-
:item-height="20"
|
|
146
|
-
item-key="id"
|
|
147
|
-
:style="{
|
|
148
|
-
border: '1px solid red',
|
|
149
|
-
boxSizing: 'border-box',
|
|
150
|
-
display: visible ? '' : 'none',
|
|
151
|
-
}"
|
|
152
|
-
@scroll="onScroll"
|
|
153
|
-
>
|
|
154
|
-
<template #default="{ item }">
|
|
155
|
-
<span
|
|
156
|
-
:style="{
|
|
157
|
-
height: `${30 + (item.id % 2 ? 0 : 10)}px`,
|
|
158
|
-
lineHeight: '30px',
|
|
159
|
-
display: 'inline-block',
|
|
160
|
-
padding: '0 8px',
|
|
161
|
-
}"
|
|
162
|
-
@click="() => console.log('Click:', item.id)"
|
|
163
|
-
>
|
|
164
|
-
{{ item.id }}
|
|
165
|
-
</span>
|
|
166
|
-
</template>
|
|
167
|
-
</VirtualList>
|
|
168
|
-
</div>
|
|
169
|
-
</template>
|
|
170
|
-
|
|
171
|
-
<style scoped>
|
|
172
|
-
button {
|
|
173
|
-
padding: 4px 8px;
|
|
174
|
-
cursor: pointer;
|
|
175
|
-
}
|
|
176
|
-
</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="{ 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>
|