Skip to content

Commit 7290dad

Browse files
committed
feat: add infinite-scroll
1 parent 319821d commit 7290dad

File tree

12 files changed

+2622
-2059
lines changed

12 files changed

+2622
-2059
lines changed

packages/components/carousel/src/Carousel.vue

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
<script lang="ts" setup>
22
import { Props } from './type'
33
import { useCarousel } from './useCarousel'
4+
import { prefixed } from '@linzhe-tools/shared'
5+
6+
const name = 'carousel'
7+
48
defineOptions({ name: 'Carousel' })
59
const props = withDefaults(defineProps<Partial<Props>>(), {
610
interval: 5000,
@@ -16,11 +20,11 @@ const {
1620
</script>
1721
<template>
1822
<div
19-
class="linzhe-tools-carousel-wrap"
23+
:class="`${prefixed}-${name}-wrap`"
2024
@mouseleave="mouseleaveHandle"
2125
@mouseenter="mouseenterHandle"
2226
>
23-
<Transition name="linzhe-tools-carousel-arrow-left">
27+
<Transition :name="`${prefixed}-${name}-arrow-left`">
2428
<div v-show="showArrow" class="btn prev-btn" @click="prevHandle">
2529
<svg width="36" height="36">
2630
<polygon
@@ -33,7 +37,7 @@ const {
3337
</svg>
3438
</div>
3539
</Transition>
36-
<Transition name="linzhe-tools-carousel-arrow-right">
40+
<Transition :name="`${prefixed}-${name}-arrow-right`">
3741
<div v-show="showArrow" class="btn next-btn" @click="nextHandle">
3842
<svg width="36" height="36">
3943
<polygon

packages/components/carousel/src/CarouselItem.vue

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
<script lang="ts" setup>
2+
import { computed } from 'vue'
23
import { useCarouselItem } from './useCarouselItem'
4+
import { prefixed } from '@linzhe-tools/shared'
5+
6+
const name = 'carousel-item'
7+
38
defineOptions({ name: 'CarouselItem' })
49
const { isAnimation, wrapItemStyle } = useCarouselItem()
10+
const classList = computed(() => {
11+
const result = {
12+
'is-animation': isAnimation.value,
13+
}
14+
result[`${prefixed}-${name}-wrap`] = true
15+
return result
16+
})
517
</script>
618
<template>
7-
<div
8-
ref="itemDomRef"
9-
class="linzhe-tools-carousel-item-wrap"
10-
:class="{ 'is-animation': isAnimation }"
11-
:style="wrapItemStyle"
12-
>
19+
<div ref="itemDomRef" :class="classList" :style="wrapItemStyle">
1320
<slot></slot>
1421
</div>
1522
</template>

packages/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ export * from './number-scroll'
33
export * from './scale-screen'
44
export * from './seamless-scroll'
55
export * from './watermark'
6+
export * from './infinite-scroll'
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import InfiniteScroll from './src/InfiniteScroll.vue'
2+
3+
export { InfiniteScroll }
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<script setup lang="ts">
2+
import { onMounted, ref, onUnmounted } from 'vue'
3+
import { prefixed } from '@linzhe-tools/shared'
4+
5+
const name = 'infinite-scroll'
6+
7+
const props = defineProps({
8+
// 当最后一个元素滚动到 <= distance到视窗时,触发新的加载
9+
// 但因为额外的检测底部96px{假设的distance} >= 新的元素的合计的高度,则这个一直在视窗内,不会触发检测了
10+
// 根据实际情况谨慎设置
11+
//! not watch this prop[distance] to rehandle
12+
distance: Number,
13+
onScrollBottom: Function,
14+
})
15+
16+
const wrapperRef = ref<HTMLElement | null>(null)
17+
const contentRef = ref<HTMLElement | null>(null)
18+
const placeholderRef = ref<HTMLElement | null>(null)
19+
20+
let enableCheckScrollBottom = false
21+
22+
let observer: IntersectionObserver | null = null
23+
const pendingOnScrollBottom = ref(false)
24+
onMounted(() => {
25+
if (contentRef.value && wrapperRef.value) {
26+
const wrapperHeight = wrapperRef.value.getBoundingClientRect().height
27+
const contentHeight = contentRef.value.getBoundingClientRect().height
28+
enableCheckScrollBottom = wrapperHeight < contentHeight
29+
const options: IntersectionObserverInit = { root: wrapperRef.value }
30+
if (props.distance) {
31+
options.rootMargin = `0px 0px ${props.distance}px 0px`
32+
}
33+
34+
observer = new IntersectionObserver(async (entries) => {
35+
const entry = entries[0]
36+
if (pendingOnScrollBottom.value === false) {
37+
if (
38+
entry.isIntersecting &&
39+
props.onScrollBottom &&
40+
enableCheckScrollBottom
41+
) {
42+
pendingOnScrollBottom.value = true
43+
await props.onScrollBottom()
44+
pendingOnScrollBottom.value = false
45+
}
46+
}
47+
}, options)
48+
observer.observe(placeholderRef.value!)
49+
}
50+
})
51+
onUnmounted(() => {
52+
if (observer) {
53+
observer.disconnect()
54+
}
55+
})
56+
</script>
57+
58+
<template>
59+
<div :class="`${prefixed}-${name}-wrapper`" ref="wrapperRef">
60+
<div :class="`${prefixed}-${name}-content`" ref="contentRef">
61+
<slot></slot>
62+
</div>
63+
<div
64+
:class="`${prefixed}-${name}-bottom-placeholder`"
65+
ref="placeholderRef"
66+
></div>
67+
<slot v-if="pendingOnScrollBottom" name="pendingOnScrollBottom"></slot>
68+
</div>
69+
</template>
70+
<style>
71+
.linzhe-tools-infinite-scroll-wrapper {
72+
height: 100%;
73+
overflow-y: auto;
74+
}
75+
</style>

packages/components/number-scroll/src/NumberScroll.vue

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
<script lang="ts" setup>
22
import { computed } from 'vue'
3+
import { prefixed } from '@linzhe-tools/shared'
4+
5+
const name = 'number-scroll'
6+
7+
defineOptions({ name: 'NumberScroll' })
38
type Props = {
49
numberString: string
510
}
611
defineProps<Props>()
7-
defineOptions({ name: 'NumberScroll' })
812
const numReg = /\d/
913
const isNumber = computed(() => (data: string) => numReg.test(data))
1014
const numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1115
</script>
1216
<template>
13-
<div class="linzhe-tools-number-scroll-wrap">
17+
<div :class="`${prefixed}-${name}-wrap`">
1418
<div v-for="(item, i) in numberString" :key="i">
1519
<div v-if="isNumber(item)" class="item">
1620
<div

packages/components/scale-screen/src/ScaleScreen.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
<script lang="ts" setup>
22
import { useScaleScreen } from './useScaleScreen'
33
import { Props } from './type'
4+
import { prefixed } from '@linzhe-tools/shared'
5+
6+
const name = 'scale-screen'
7+
48
defineOptions({ name: 'ScaleScreen' })
59
const props = withDefaults(defineProps<Partial<Props>>(), {
610
height: 1080,
@@ -19,7 +23,7 @@ const {
1923
defineExpose({ fullScreen, exitScreen })
2024
</script>
2125
<template>
22-
<div class="linzhe-tools-scale-screen-wrap" ref="wrapper">
26+
<div :class="`${prefixed}-${name}-wrap`" ref="wrapper">
2327
<div class="container" ref="scaleWrapper" :style="scaleWrapperStyle">
2428
<slot :slotProps="slotProps"></slot>
2529
</div>

packages/components/seamless-scroll/src/SeamlessScroll.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
<script lang="ts" setup>
22
import { Props } from './type'
33
import { useSeamlessScroll } from './useSeamlessScroll'
4+
import { prefixed } from '@linzhe-tools/shared'
5+
6+
const name = 'seamless-scroll'
7+
48
defineOptions({ name: 'SeamlessScroll' })
59
const props = withDefaults(defineProps<Partial<Props>>(), {
610
height: 500,
@@ -18,7 +22,7 @@ const {
1822
</script>
1923
<template>
2024
<div
21-
class="linzhe-tools-seamless-scroll-wrap"
25+
:class="`${prefixed}-${name}-wrap`"
2226
:style="{ height: height + 'px', overflow: 'hidden' }"
2327
>
2428
<div

packages/components/watermark/src/Watermark.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
<script lang="ts" setup>
22
import { Props } from './type'
33
import { useWatermark } from './useWatermark'
4+
import { prefixed } from '@linzhe-tools/shared'
5+
6+
const name = 'watermark'
7+
48
defineOptions({ name: 'Watermark' })
59
const props = withDefaults(defineProps<Partial<Props>>(), {
610
text: '',
@@ -11,7 +15,7 @@ const props = withDefaults(defineProps<Partial<Props>>(), {
1115
const { watermarkWrapper } = useWatermark(props)
1216
</script>
1317
<template>
14-
<div class="linzhe-tools-watermark-wrap">
18+
<div :class="`${prefixed}-${name}-wrap`">
1519
<div class="container" ref="watermarkWrapper">
1620
<slot></slot>
1721
</div>

packages/shared/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ export function debounce(fn: (...args: any[]) => any, delay: number = 100) {
88
}, delay)
99
}
1010
}
11+
12+
export const prefixed = 'linzhe-tools'

0 commit comments

Comments
 (0)