@v-c/virtual-list 1.0.0 → 1.0.2
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 +18 -9
- package/dist/List.js +19 -10
- 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
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import type { Ref } from 'vue'
|
|
2
|
-
import { onUnmounted, ref, watch } from 'vue'
|
|
3
|
-
|
|
4
|
-
const SMOOTH_PTG = 14 / 15
|
|
5
|
-
|
|
6
|
-
export default function useMobileTouchMove(
|
|
7
|
-
inVirtual: Ref<boolean>,
|
|
8
|
-
listRef: Ref<HTMLDivElement | null | undefined>,
|
|
9
|
-
callback: (
|
|
10
|
-
isHorizontal: boolean,
|
|
11
|
-
offset: number,
|
|
12
|
-
smoothOffset: boolean,
|
|
13
|
-
e?: TouchEvent,
|
|
14
|
-
) => boolean,
|
|
15
|
-
) {
|
|
16
|
-
const touchedRef = ref(false)
|
|
17
|
-
const touchXRef = ref(0)
|
|
18
|
-
const touchYRef = ref(0)
|
|
19
|
-
|
|
20
|
-
let elementRef: HTMLElement | null = null
|
|
21
|
-
let touchStartElement: HTMLDivElement | null = null
|
|
22
|
-
|
|
23
|
-
// Smooth scroll
|
|
24
|
-
let intervalId: ReturnType<typeof setInterval> | null = null
|
|
25
|
-
|
|
26
|
-
let cleanUpEvents: () => void
|
|
27
|
-
|
|
28
|
-
const onTouchMove = (e: TouchEvent) => {
|
|
29
|
-
if (touchedRef.value) {
|
|
30
|
-
const currentX = Math.ceil(e.touches[0].pageX)
|
|
31
|
-
const currentY = Math.ceil(e.touches[0].pageY)
|
|
32
|
-
let offsetX = touchXRef.value - currentX
|
|
33
|
-
let offsetY = touchYRef.value - currentY
|
|
34
|
-
const isHorizontal = Math.abs(offsetX) > Math.abs(offsetY)
|
|
35
|
-
if (isHorizontal) {
|
|
36
|
-
touchXRef.value = currentX
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
touchYRef.value = currentY
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const scrollHandled = callback(isHorizontal, isHorizontal ? offsetX : offsetY, false, e)
|
|
43
|
-
if (scrollHandled) {
|
|
44
|
-
e.preventDefault()
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Smooth interval
|
|
48
|
-
if (intervalId)
|
|
49
|
-
clearInterval(intervalId)
|
|
50
|
-
|
|
51
|
-
if (scrollHandled) {
|
|
52
|
-
intervalId = setInterval(() => {
|
|
53
|
-
if (isHorizontal) {
|
|
54
|
-
offsetX *= SMOOTH_PTG
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
offsetY *= SMOOTH_PTG
|
|
58
|
-
}
|
|
59
|
-
const offset = Math.floor(isHorizontal ? offsetX : offsetY)
|
|
60
|
-
if (!callback(isHorizontal, offset, true) || Math.abs(offset) <= 0.1) {
|
|
61
|
-
if (intervalId)
|
|
62
|
-
clearInterval(intervalId)
|
|
63
|
-
}
|
|
64
|
-
}, 16)
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const onTouchEnd = () => {
|
|
70
|
-
touchedRef.value = false
|
|
71
|
-
|
|
72
|
-
cleanUpEvents()
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const onTouchStart = (e: TouchEvent) => {
|
|
76
|
-
cleanUpEvents()
|
|
77
|
-
|
|
78
|
-
if (e.touches.length === 1 && !touchedRef.value) {
|
|
79
|
-
touchedRef.value = true
|
|
80
|
-
touchXRef.value = Math.ceil(e.touches[0].pageX)
|
|
81
|
-
touchYRef.value = Math.ceil(e.touches[0].pageY)
|
|
82
|
-
|
|
83
|
-
elementRef = e.target as HTMLElement
|
|
84
|
-
elementRef.addEventListener('touchmove', onTouchMove, { passive: false })
|
|
85
|
-
elementRef.addEventListener('touchend', onTouchEnd, { passive: true } as any)
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
cleanUpEvents = () => {
|
|
90
|
-
if (elementRef) {
|
|
91
|
-
elementRef.removeEventListener('touchmove', onTouchMove)
|
|
92
|
-
elementRef.removeEventListener('touchend', onTouchEnd)
|
|
93
|
-
elementRef = null
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const removeTouchStartListener = () => {
|
|
98
|
-
if (touchStartElement) {
|
|
99
|
-
touchStartElement.removeEventListener('touchstart', onTouchStart)
|
|
100
|
-
touchStartElement = null
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const teardown = () => {
|
|
105
|
-
removeTouchStartListener()
|
|
106
|
-
cleanUpEvents()
|
|
107
|
-
if (intervalId) {
|
|
108
|
-
clearInterval(intervalId)
|
|
109
|
-
intervalId = null
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
onUnmounted(teardown)
|
|
114
|
-
|
|
115
|
-
watch(
|
|
116
|
-
[inVirtual, listRef],
|
|
117
|
-
([enabled, ele], _prev, onCleanup) => {
|
|
118
|
-
if (enabled && ele) {
|
|
119
|
-
touchStartElement = ele
|
|
120
|
-
ele.addEventListener('touchstart', onTouchStart, { passive: true } as any)
|
|
121
|
-
|
|
122
|
-
onCleanup(() => {
|
|
123
|
-
teardown()
|
|
124
|
-
})
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
teardown()
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
{ immediate: true },
|
|
131
|
-
)
|
|
132
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import type { Ref } from 'vue'
|
|
2
|
-
import { ref } from 'vue'
|
|
3
|
-
|
|
4
|
-
export default function useOriginScroll(
|
|
5
|
-
isScrollAtTop: Ref<boolean>,
|
|
6
|
-
isScrollAtBottom: Ref<boolean>,
|
|
7
|
-
isScrollAtLeft: Ref<boolean>,
|
|
8
|
-
isScrollAtRight: Ref<boolean>,
|
|
9
|
-
) {
|
|
10
|
-
// Do lock for a wheel when scrolling
|
|
11
|
-
const lockRef = ref(false)
|
|
12
|
-
let lockTimeout: ReturnType<typeof setTimeout> | null = null
|
|
13
|
-
|
|
14
|
-
function lockScroll() {
|
|
15
|
-
if (lockTimeout)
|
|
16
|
-
clearTimeout(lockTimeout)
|
|
17
|
-
|
|
18
|
-
lockRef.value = true
|
|
19
|
-
|
|
20
|
-
lockTimeout = setTimeout(() => {
|
|
21
|
-
lockRef.value = false
|
|
22
|
-
}, 50)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return (isHorizontal: boolean, delta: number, smoothOffset = false) => {
|
|
26
|
-
const originScroll = isHorizontal
|
|
27
|
-
// Pass origin wheel when on the left
|
|
28
|
-
? (delta < 0 && isScrollAtLeft.value)
|
|
29
|
-
// Pass origin wheel when on the right
|
|
30
|
-
|| (delta > 0 && isScrollAtRight.value)
|
|
31
|
-
// Pass origin wheel when on the top
|
|
32
|
-
: (delta < 0 && isScrollAtTop.value)
|
|
33
|
-
// Pass origin wheel when on the bottom
|
|
34
|
-
|| (delta > 0 && isScrollAtBottom.value)
|
|
35
|
-
|
|
36
|
-
if (smoothOffset && originScroll) {
|
|
37
|
-
// No need lock anymore when it's smooth offset from touchMove interval
|
|
38
|
-
if (lockTimeout)
|
|
39
|
-
clearTimeout(lockTimeout)
|
|
40
|
-
lockRef.value = false
|
|
41
|
-
}
|
|
42
|
-
else if (!originScroll || lockRef.value) {
|
|
43
|
-
lockScroll()
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return !lockRef.value && originScroll
|
|
47
|
-
}
|
|
48
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import type { Ref } from 'vue'
|
|
2
|
-
import { onUnmounted, watch } from 'vue'
|
|
3
|
-
|
|
4
|
-
function smoothScrollOffset(offset: number) {
|
|
5
|
-
return Math.floor(offset ** 0.5)
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function getPageXY(
|
|
9
|
-
e: MouseEvent | TouchEvent,
|
|
10
|
-
horizontal: boolean,
|
|
11
|
-
): number {
|
|
12
|
-
const obj = 'touches' in e ? e.touches[0] : e
|
|
13
|
-
return obj[horizontal ? 'pageX' : 'pageY'] - window[horizontal ? 'scrollX' : 'scrollY']
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export default function useScrollDrag(
|
|
17
|
-
inVirtual: Ref<boolean>,
|
|
18
|
-
componentRef: Ref<HTMLElement | null | undefined>,
|
|
19
|
-
onScrollOffset: (offset: number) => void,
|
|
20
|
-
) {
|
|
21
|
-
let cachedElement: HTMLElement | null = null
|
|
22
|
-
let cachedDocument: Document | null = null
|
|
23
|
-
let mouseDownLock = false
|
|
24
|
-
let rafId: number | null = null
|
|
25
|
-
let offset = 0
|
|
26
|
-
|
|
27
|
-
const stopScroll = () => {
|
|
28
|
-
if (rafId !== null) {
|
|
29
|
-
cancelAnimationFrame(rafId)
|
|
30
|
-
rafId = null
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const continueScroll = () => {
|
|
35
|
-
stopScroll()
|
|
36
|
-
|
|
37
|
-
rafId = requestAnimationFrame(() => {
|
|
38
|
-
onScrollOffset(offset)
|
|
39
|
-
continueScroll()
|
|
40
|
-
})
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const clearDragState = () => {
|
|
44
|
-
mouseDownLock = false
|
|
45
|
-
stopScroll()
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const onMouseDown = (e: MouseEvent) => {
|
|
49
|
-
// Skip if element set draggable
|
|
50
|
-
if ((e.target as HTMLElement).draggable || e.button !== 0) {
|
|
51
|
-
return
|
|
52
|
-
}
|
|
53
|
-
// Skip if nest List has handled this event
|
|
54
|
-
const event = e as MouseEvent & {
|
|
55
|
-
_virtualHandled?: boolean
|
|
56
|
-
}
|
|
57
|
-
if (!event._virtualHandled) {
|
|
58
|
-
event._virtualHandled = true
|
|
59
|
-
mouseDownLock = true
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const onMouseMove = (e: MouseEvent) => {
|
|
64
|
-
if (mouseDownLock && cachedElement) {
|
|
65
|
-
const mouseY = getPageXY(e, false)
|
|
66
|
-
const { top, bottom } = cachedElement.getBoundingClientRect()
|
|
67
|
-
|
|
68
|
-
if (mouseY <= top) {
|
|
69
|
-
const diff = top - mouseY
|
|
70
|
-
offset = -smoothScrollOffset(diff)
|
|
71
|
-
continueScroll()
|
|
72
|
-
}
|
|
73
|
-
else if (mouseY >= bottom) {
|
|
74
|
-
const diff = mouseY - bottom
|
|
75
|
-
offset = smoothScrollOffset(diff)
|
|
76
|
-
continueScroll()
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
stopScroll()
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const teardown = () => {
|
|
85
|
-
if (cachedElement) {
|
|
86
|
-
cachedElement.removeEventListener('mousedown', onMouseDown)
|
|
87
|
-
cachedElement = null
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (cachedDocument) {
|
|
91
|
-
cachedDocument.removeEventListener('mouseup', clearDragState)
|
|
92
|
-
cachedDocument.removeEventListener('mousemove', onMouseMove)
|
|
93
|
-
cachedDocument.removeEventListener('dragend', clearDragState)
|
|
94
|
-
cachedDocument = null
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
clearDragState()
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
onUnmounted(teardown)
|
|
101
|
-
|
|
102
|
-
watch(
|
|
103
|
-
[inVirtual, componentRef],
|
|
104
|
-
([enabled, ele], _prev, onCleanup) => {
|
|
105
|
-
if (enabled && ele) {
|
|
106
|
-
cachedElement = ele
|
|
107
|
-
cachedDocument = ele.ownerDocument
|
|
108
|
-
|
|
109
|
-
cachedElement.addEventListener('mousedown', onMouseDown)
|
|
110
|
-
cachedDocument.addEventListener('mouseup', clearDragState)
|
|
111
|
-
cachedDocument.addEventListener('mousemove', onMouseMove)
|
|
112
|
-
cachedDocument.addEventListener('dragend', clearDragState)
|
|
113
|
-
|
|
114
|
-
onCleanup(() => {
|
|
115
|
-
teardown()
|
|
116
|
-
})
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
teardown()
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
{ immediate: true },
|
|
123
|
-
)
|
|
124
|
-
}
|
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import type { Key } from '@v-c/util/dist/type'
|
|
2
|
-
import type { Ref } from 'vue'
|
|
3
|
-
import type { GetKey } from '../interface.ts'
|
|
4
|
-
import type CacheMap from '../utils/CacheMap.ts'
|
|
5
|
-
import { warning } from '@v-c/util'
|
|
6
|
-
import raf from '@v-c/util/dist/raf'
|
|
7
|
-
import { shallowRef, watch } from 'vue'
|
|
8
|
-
|
|
9
|
-
const MAX_TIMES = 10
|
|
10
|
-
|
|
11
|
-
export type ScrollAlign = 'top' | 'bottom' | 'auto'
|
|
12
|
-
|
|
13
|
-
export interface ScrollPos {
|
|
14
|
-
left?: number
|
|
15
|
-
top?: number
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export type ScrollTarget = {
|
|
19
|
-
index: number
|
|
20
|
-
align?: ScrollAlign
|
|
21
|
-
offset?: number
|
|
22
|
-
} | {
|
|
23
|
-
key: Key
|
|
24
|
-
align?: ScrollAlign
|
|
25
|
-
offset?: number
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export default function useScrollTo(
|
|
29
|
-
containerRef: Ref<HTMLDivElement>,
|
|
30
|
-
data: Ref<any[]>,
|
|
31
|
-
heights: CacheMap,
|
|
32
|
-
itemHeight: Ref<number>,
|
|
33
|
-
getKey: GetKey<any>,
|
|
34
|
-
collectHeight: () => void,
|
|
35
|
-
syncScrollTop: (newTop: number) => void,
|
|
36
|
-
triggerFlash: () => void,
|
|
37
|
-
): (arg: number | ScrollTarget) => void {
|
|
38
|
-
const scrollRef = shallowRef<number>()
|
|
39
|
-
|
|
40
|
-
const syncState = shallowRef<{
|
|
41
|
-
times: number
|
|
42
|
-
index: number
|
|
43
|
-
offset: number
|
|
44
|
-
originAlign: ScrollAlign
|
|
45
|
-
targetAlign?: 'top' | 'bottom'
|
|
46
|
-
lastTop?: number
|
|
47
|
-
} | null>(null)
|
|
48
|
-
|
|
49
|
-
// ========================== Sync Scroll ==========================
|
|
50
|
-
watch(
|
|
51
|
-
[syncState, containerRef],
|
|
52
|
-
() => {
|
|
53
|
-
if (syncState.value && syncState.value.times < MAX_TIMES) {
|
|
54
|
-
// Never reach
|
|
55
|
-
if (!containerRef.value) {
|
|
56
|
-
syncState.value = { ...syncState.value }
|
|
57
|
-
return
|
|
58
|
-
}
|
|
59
|
-
collectHeight()
|
|
60
|
-
const { targetAlign, originAlign, index, offset } = syncState.value
|
|
61
|
-
|
|
62
|
-
const height = containerRef.value.clientHeight
|
|
63
|
-
let needCollectHeight = false
|
|
64
|
-
let newTargetAlign: 'top' | 'bottom' | null = targetAlign ?? null
|
|
65
|
-
let targetTop: number | null = null
|
|
66
|
-
// Go to next frame if height not exist
|
|
67
|
-
if (height) {
|
|
68
|
-
const mergedAlign = targetAlign || originAlign
|
|
69
|
-
// Get top & bottom
|
|
70
|
-
let stackTop = 0
|
|
71
|
-
let itemTop = 0
|
|
72
|
-
let itemBottom = 0
|
|
73
|
-
|
|
74
|
-
const maxLen = Math.min(data.value.length - 1, index)
|
|
75
|
-
|
|
76
|
-
for (let i = 0; i <= maxLen; i += 1) {
|
|
77
|
-
const key = getKey(data.value[i])
|
|
78
|
-
itemTop = stackTop
|
|
79
|
-
const cacheHeight = heights.get(key)
|
|
80
|
-
itemBottom = itemTop + (cacheHeight === undefined ? itemHeight.value : cacheHeight)
|
|
81
|
-
|
|
82
|
-
stackTop = itemBottom
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Check if need sync height (visible range has item not record height)
|
|
86
|
-
let leftHeight = mergedAlign === 'top' ? offset : height - offset
|
|
87
|
-
for (let i = maxLen; i >= 0; i -= 1) {
|
|
88
|
-
const key = getKey(data.value[i])
|
|
89
|
-
const cacheHeight = heights.get(key)
|
|
90
|
-
|
|
91
|
-
if (cacheHeight === undefined) {
|
|
92
|
-
needCollectHeight = true
|
|
93
|
-
break
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
leftHeight -= cacheHeight
|
|
97
|
-
if (leftHeight <= 0) {
|
|
98
|
-
break
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Scroll to
|
|
103
|
-
switch (mergedAlign) {
|
|
104
|
-
case 'top':
|
|
105
|
-
targetTop = itemTop - offset
|
|
106
|
-
break
|
|
107
|
-
case 'bottom':
|
|
108
|
-
targetTop = itemBottom - height + offset
|
|
109
|
-
break
|
|
110
|
-
|
|
111
|
-
default: {
|
|
112
|
-
const { scrollTop } = containerRef.value
|
|
113
|
-
const scrollBottom = scrollTop + height
|
|
114
|
-
if (itemTop < scrollTop) {
|
|
115
|
-
newTargetAlign = 'top'
|
|
116
|
-
}
|
|
117
|
-
else if (itemBottom > scrollBottom) {
|
|
118
|
-
newTargetAlign = 'bottom'
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
if (targetTop !== null) {
|
|
123
|
-
syncScrollTop(targetTop)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// One more time for sync
|
|
127
|
-
if (targetTop !== syncState.value.lastTop) {
|
|
128
|
-
needCollectHeight = true
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (needCollectHeight) {
|
|
133
|
-
syncState.value = {
|
|
134
|
-
...syncState.value,
|
|
135
|
-
times: syncState.value.times + 1,
|
|
136
|
-
targetAlign: newTargetAlign as any,
|
|
137
|
-
lastTop: targetTop as any,
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
else if (process.env.NODE_ENV !== 'production' && syncState.value?.times === MAX_TIMES) {
|
|
142
|
-
warning(
|
|
143
|
-
false,
|
|
144
|
-
'Seems `scrollTo` with `rc-virtual-list` reach the max limitation. Please fire issue for us. Thanks.',
|
|
145
|
-
)
|
|
146
|
-
}
|
|
147
|
-
},
|
|
148
|
-
{
|
|
149
|
-
immediate: true,
|
|
150
|
-
flush: 'post',
|
|
151
|
-
},
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
// =========================== Scroll To ===========================
|
|
155
|
-
return (arg) => {
|
|
156
|
-
if (arg === null || arg === undefined) {
|
|
157
|
-
triggerFlash()
|
|
158
|
-
return
|
|
159
|
-
}
|
|
160
|
-
// Normalize target
|
|
161
|
-
raf.cancel(scrollRef.value!)
|
|
162
|
-
if (typeof arg === 'number') {
|
|
163
|
-
syncScrollTop(arg)
|
|
164
|
-
}
|
|
165
|
-
else if (arg && typeof arg === 'object') {
|
|
166
|
-
let index: number
|
|
167
|
-
const { align } = arg
|
|
168
|
-
if ('index' in arg) {
|
|
169
|
-
({ index } = arg)
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
index = data.value.findIndex(item => getKey(item) === arg.key)
|
|
173
|
-
}
|
|
174
|
-
const { offset = 0 } = arg
|
|
175
|
-
|
|
176
|
-
syncState.value = {
|
|
177
|
-
times: 0,
|
|
178
|
-
index,
|
|
179
|
-
offset,
|
|
180
|
-
originAlign: align!,
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
package/src/index.ts
DELETED
package/src/interface.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { Key } from '@v-c/util/dist/type'
|
|
2
|
-
import type { CSSProperties, VNode } from 'vue'
|
|
3
|
-
|
|
4
|
-
export type RenderFunc<T> = (
|
|
5
|
-
item: T,
|
|
6
|
-
index: number,
|
|
7
|
-
props: { style: CSSProperties, offsetX: number },
|
|
8
|
-
) => VNode
|
|
9
|
-
|
|
10
|
-
export interface SharedConfig<T> {
|
|
11
|
-
getKey: (item: T) => Key
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export type GetKey<T> = (item: T) => Key
|
|
15
|
-
|
|
16
|
-
export type GetSize = (startKey: Key, endKey?: Key) => { top: number, bottom: number }
|
|
17
|
-
|
|
18
|
-
export interface ExtraRenderInfo {
|
|
19
|
-
/** Virtual list start line */
|
|
20
|
-
start: number
|
|
21
|
-
/** Virtual list end line */
|
|
22
|
-
end: number
|
|
23
|
-
/** Is current in virtual render */
|
|
24
|
-
virtual: boolean
|
|
25
|
-
/** Used for `scrollWidth` tell the horizontal offset */
|
|
26
|
-
offsetX: number
|
|
27
|
-
offsetY: number
|
|
28
|
-
|
|
29
|
-
rtl: boolean
|
|
30
|
-
|
|
31
|
-
getSize: GetSize
|
|
32
|
-
}
|
package/src/utils/CacheMap.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import type { Key } from '@v-c/util/dist/type'
|
|
2
|
-
|
|
3
|
-
// Firefox has low performance of map.
|
|
4
|
-
class CacheMap {
|
|
5
|
-
maps: Record<string, number>
|
|
6
|
-
|
|
7
|
-
// Used for cache key
|
|
8
|
-
// `useMemo` no need to update if `id` not change
|
|
9
|
-
id: number = 0
|
|
10
|
-
|
|
11
|
-
diffRecords = new Map<Key, number>()
|
|
12
|
-
|
|
13
|
-
constructor() {
|
|
14
|
-
this.maps = Object.create(null)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
set(key: Key, value: number) {
|
|
18
|
-
// Record prev value
|
|
19
|
-
this.diffRecords.set(key, this.maps[key as string])
|
|
20
|
-
|
|
21
|
-
this.maps[key as string] = value
|
|
22
|
-
this.id += 1
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
get(key: Key) {
|
|
26
|
-
return this.maps[key as string]
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* CacheMap will record the key changed.
|
|
31
|
-
* To help to know what's update in the next render.
|
|
32
|
-
*/
|
|
33
|
-
resetRecord() {
|
|
34
|
-
this.diffRecords.clear()
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
getRecord() {
|
|
38
|
-
return this.diffRecords
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export default CacheMap
|
package/src/utils/isFirefox.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
const MIN_SIZE = 20
|
|
2
|
-
|
|
3
|
-
export function getSpinSize(containerSize = 0, scrollRange = 0) {
|
|
4
|
-
let baseSize = (containerSize / scrollRange) * containerSize
|
|
5
|
-
if (isNaN(baseSize)) {
|
|
6
|
-
baseSize = 0
|
|
7
|
-
}
|
|
8
|
-
baseSize = Math.max(baseSize, MIN_SIZE)
|
|
9
|
-
return Math.floor(baseSize)
|
|
10
|
-
}
|
package/tsconfig.json
DELETED
package/vite.config.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { UserConfig } from 'vite'
|
|
2
|
-
import fg from 'fast-glob'
|
|
3
|
-
import { defineConfig, mergeConfig } from 'vite'
|
|
4
|
-
import { buildCommon } from '../../scripts/build.common'
|
|
5
|
-
|
|
6
|
-
const entry = fg.sync(['src/**/*.ts', 'src/**/*.tsx', '!src/**/*.test.ts', '!src/**/*.test.tsx', '!src/**/tests'])
|
|
7
|
-
|
|
8
|
-
export default defineConfig({
|
|
9
|
-
...mergeConfig(buildCommon({
|
|
10
|
-
external: ['vue', /^@v-c\//],
|
|
11
|
-
}), {
|
|
12
|
-
build: {
|
|
13
|
-
lib: {
|
|
14
|
-
entry,
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
} as UserConfig),
|
|
18
|
-
})
|