Skip to content

Commit aace7e0

Browse files
committed
fix: autoplay
Signed-off-by: Innei <tukon479@gmail.com>
1 parent 8c68b41 commit aace7e0

File tree

3 files changed

+57
-21
lines changed

3 files changed

+57
-21
lines changed

src/components/universal/Markdown/components/gallery/index.module.css

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
.root {
2+
&:hover .indicator {
3+
opacity: 1;
4+
}
5+
}
6+
17
.container {
28
scroll-snap-type: x mandatory;
39
display: flex;
@@ -20,7 +26,8 @@
2026
}
2127

2228
.indicator {
23-
@apply absolute bottom-[24px] left-[50%] flex bg-bg-opacity rounded-[24px] z-1 px-6 py-4;
29+
@apply absolute bottom-[24px] left-[50%] flex bg-bg-opacity rounded-[24px] z-1 px-6 py-4 opacity-0;
30+
@apply transition-opacity duration-300;
2431

2532
transform: translateX(-50%);
2633
backdrop-filter: blur(20px) saturate(180%);

src/components/universal/Markdown/components/gallery/index.tsx

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@ import { calculateDimensions } from '~/utils/images'
1919
import type { MImageType } from '../../utils/image'
2020
import styles from './index.module.css'
2121

22+
const IMAGE_CONTAINER_MARGIN_INSET = 60
23+
const CHILD_GAP = 15
24+
const AUTOPLAY_DURATION = 5000
25+
2226
interface GalleryProps {
2327
images: MImageType[]
2428
}
25-
const IMAGE_CONTAINER_MARGIN_INSET = 60
26-
const CHILD_GAP = 15
29+
2730
export const Gallery: FC<GalleryProps> = (props) => {
2831
const { images } = props
2932
const imageMeta = useContext(ImageSizeMetaContext)
@@ -69,7 +72,7 @@ export const Gallery: FC<GalleryProps> = (props) => {
6972

7073
// eslint-disable-next-line react-hooks/exhaustive-deps
7174
const handleOnScroll: UIEventHandler<HTMLDivElement> = useCallback(
72-
throttle((e) => {
75+
throttle<UIEventHandler<HTMLDivElement>>((e) => {
7376
const $ = e.target as HTMLDivElement
7477

7578
const index = Math.floor(
@@ -81,15 +84,14 @@ export const Gallery: FC<GalleryProps> = (props) => {
8184
[],
8285
)
8386
const handleScrollTo = useCallback(
84-
(i: number, animated = true) => {
85-
autoplayTimerRef.current = clearInterval(autoplayTimerRef.current)
87+
(i: number) => {
8688
if (!containerRef) {
8789
return
8890
}
8991

9092
containerRef.scrollTo({
9193
left: memoedChildContainerWidthRef.current * i,
92-
behavior: animated ? 'smooth' : 'auto',
94+
behavior: 'smooth',
9395
})
9496
},
9597
[containerRef],
@@ -98,14 +100,43 @@ export const Gallery: FC<GalleryProps> = (props) => {
98100
const autoplayTimerRef = useRef(null as any)
99101

100102
const currentIndexRef = useStateRef(currentIndex)
103+
const totalImageLengthRef = useStateRef(images.length)
104+
105+
// 向后翻页状态
106+
const isForward = useRef(true)
107+
108+
const autoplayRef = useRef(true)
109+
const handleCancelAutoplay = useCallback(() => {
110+
if (!autoplayRef.current) {
111+
return
112+
}
113+
114+
autoplayRef.current = false
115+
clearInterval(autoplayTimerRef.current)
116+
}, [])
117+
101118
const { ref } = useInView({
102119
initialInView: false,
120+
triggerOnce: images.length < 2,
103121
onChange(inView) {
122+
if (totalImageLengthRef.current < 2 || !autoplayRef.current) {
123+
return
124+
}
104125
if (inView) {
105126
autoplayTimerRef.current = setInterval(() => {
106-
const index = (currentIndexRef.current + 1) % images.length
107-
handleScrollTo(index, index == 0 ? false : true)
108-
}, 3000)
127+
if (
128+
currentIndexRef.current + 1 > totalImageLengthRef.current - 1 &&
129+
isForward.current
130+
) {
131+
isForward.current = false
132+
}
133+
if (currentIndexRef.current - 1 < 0 && !isForward.current) {
134+
isForward.current = true
135+
}
136+
137+
const index = currentIndexRef.current + (isForward.current ? 1 : -1)
138+
handleScrollTo(index)
139+
}, AUTOPLAY_DURATION)
109140
} else {
110141
autoplayTimerRef.current = clearInterval(autoplayTimerRef.current)
111142
}
@@ -119,7 +150,12 @@ export const Gallery: FC<GalleryProps> = (props) => {
119150
}, [])
120151

121152
return (
122-
<div className={clsx('w-full', 'relative')} ref={ref}>
153+
<div
154+
className={clsx('w-full', 'relative', styles['root'])}
155+
ref={ref}
156+
onWheel={handleCancelAutoplay}
157+
onTouchStart={handleCancelAutoplay}
158+
>
123159
<div
124160
className={clsx(
125161
'w-full whitespace-nowrap overflow-auto',
@@ -173,7 +209,7 @@ export const Gallery: FC<GalleryProps> = (props) => {
173209
return (
174210
<div
175211
className={clsx(
176-
'h-[6px] w-[6px] rounded-full bg-light-font opacity-50 transition-opacity duration-200 ease-in-out cursor-pointer',
212+
'h-[6px] w-[6px] rounded-full bg-dark-50 opacity-50 transition-opacity duration-200 ease-in-out cursor-pointer',
177213
currentIndex == i && '!opacity-100',
178214
)}
179215
key={i}

src/hooks/use-state-ref.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
import type { MutableRefObject } from 'react'
2-
import { useEffect, useRef } from 'react'
1+
import { useStateToRef } from 'react-shortcut-guide'
32

4-
export const useStateRef = <T>(state: T): MutableRefObject<T> => {
5-
const ref = useRef<T>(state)
6-
useEffect(() => {
7-
ref.current = state
8-
}, [state])
9-
return ref
10-
}
3+
export const useStateRef = useStateToRef

0 commit comments

Comments
 (0)