@@ -5,60 +5,100 @@ import { partnersRawData } from '@/data/partners'
55import styles from './Partners.module.css'
66
77export default function PartnersSection ( ) {
8- const scrollRef = useRef < HTMLDivElement > ( null )
8+ const scrollRef1 = useRef < HTMLDivElement > ( null )
9+ const scrollRef2 = useRef < HTMLDivElement > ( null )
910
10- // 只显示有logo的合作伙伴,不区分时间和等级
11- const validPartners = partnersRawData . filter (
12- partner => partner . logo &&
13- partner . logo !== '/logo.png' &&
14- partner . logo . trim ( ) !== ''
15- )
11+ // 只显示有logo的合作伙伴,不区分时间和等级,并根据title去重
12+ const validPartners = partnersRawData
13+ . filter (
14+ partner => partner . logo &&
15+ partner . logo !== '/logo.png' &&
16+ partner . logo . trim ( ) !== ''
17+ )
18+ . reduce < typeof partnersRawData > ( ( acc , partner ) => {
19+ // 检查是否已存在相同title的合作伙伴
20+ const existingIndex = acc . findIndex ( existing => existing . title === partner . title )
21+ if ( existingIndex === - 1 ) {
22+ // 如果不存在,直接添加
23+ acc . push ( partner )
24+ }
25+ return acc
26+ } , [ ] )
1627
17- // 将合作伙伴数组复制一份以实现无缝轮播
18- const duplicatedPartners = [ ...validPartners , ...validPartners ]
28+ // 将合作伙伴数组分成两组
29+ const midIndex = Math . ceil ( validPartners . length / 2 )
30+ const firstRowPartners = [ ...validPartners . slice ( 0 , midIndex ) , ...validPartners . slice ( 0 , midIndex ) ]
31+ const secondRowPartners = [ ...validPartners . slice ( midIndex ) , ...validPartners . slice ( midIndex ) ]
1932
2033 useEffect ( ( ) => {
21- let animationFrame : number
22- const scrollContainer = scrollRef . current
34+ let animationFrame1 : number
35+ let animationFrame2 : number
36+ const scrollContainer1 = scrollRef1 . current
37+ const scrollContainer2 = scrollRef2 . current
2338
24- const scroll = ( ) => {
25- if ( scrollContainer ) {
26- scrollContainer . scrollLeft += 1
39+ const scroll1 = ( ) => {
40+ if ( scrollContainer1 ) {
41+ scrollContainer1 . scrollLeft += 1
2742
2843 // 当滚动到一半时重置到开始位置,实现无缝循环
29- if ( scrollContainer . scrollLeft >= scrollContainer . scrollWidth / 2 ) {
30- scrollContainer . scrollLeft = 0
44+ if ( scrollContainer1 . scrollLeft >= scrollContainer1 . scrollWidth / 2 ) {
45+ scrollContainer1 . scrollLeft = 0
46+ }
47+ }
48+ animationFrame1 = requestAnimationFrame ( scroll1 )
49+ }
50+
51+ const scroll2 = ( ) => {
52+ if ( scrollContainer2 ) {
53+ scrollContainer2 . scrollLeft -= 1
54+
55+ // 当滚动到开始位置时重置到一半位置,实现反向无缝循环
56+ if ( scrollContainer2 . scrollLeft <= 0 ) {
57+ scrollContainer2 . scrollLeft = scrollContainer2 . scrollWidth / 2
3158 }
3259 }
33- animationFrame = requestAnimationFrame ( scroll )
60+ animationFrame2 = requestAnimationFrame ( scroll2 )
3461 }
3562
3663 // 开始自动滚动
3764 const startScrolling = ( ) => {
38- animationFrame = requestAnimationFrame ( scroll )
65+ animationFrame1 = requestAnimationFrame ( scroll1 )
66+ animationFrame2 = requestAnimationFrame ( scroll2 )
3967 }
4068
4169 // 停止自动滚动
4270 const stopScrolling = ( ) => {
43- cancelAnimationFrame ( animationFrame )
71+ cancelAnimationFrame ( animationFrame1 )
72+ cancelAnimationFrame ( animationFrame2 )
4473 }
4574
4675 // 添加鼠标事件监听器
47- if ( scrollContainer ) {
48- scrollContainer . addEventListener ( 'mouseenter' , stopScrolling )
49- scrollContainer . addEventListener ( 'mouseleave' , startScrolling )
76+ const containers = [ scrollContainer1 , scrollContainer2 ]
77+ containers . forEach ( container => {
78+ if ( container ) {
79+ container . addEventListener ( 'mouseenter' , stopScrolling )
80+ container . addEventListener ( 'mouseleave' , startScrolling )
81+ }
82+ } )
83+
84+ // 初始化第二行的滚动位置
85+ if ( scrollContainer2 ) {
86+ scrollContainer2 . scrollLeft = scrollContainer2 . scrollWidth / 2
5087 }
5188
5289 // 启动轮播
5390 startScrolling ( )
5491
5592 // 清理函数
5693 return ( ) => {
57- cancelAnimationFrame ( animationFrame )
58- if ( scrollContainer ) {
59- scrollContainer . removeEventListener ( 'mouseenter' , stopScrolling )
60- scrollContainer . removeEventListener ( 'mouseleave' , startScrolling )
61- }
94+ cancelAnimationFrame ( animationFrame1 )
95+ cancelAnimationFrame ( animationFrame2 )
96+ containers . forEach ( container => {
97+ if ( container ) {
98+ container . removeEventListener ( 'mouseenter' , stopScrolling )
99+ container . removeEventListener ( 'mouseleave' , startScrolling )
100+ }
101+ } )
62102 }
63103 } , [ ] )
64104
@@ -72,29 +112,60 @@ export default function PartnersSection() {
72112 < div className = { styles . blockDivider } > </ div >
73113 </ div >
74114
75- < div className = { styles . partnersCarousel } >
76- < div
77- ref = { scrollRef }
78- className = { styles . partnersScroll }
79- >
80- < div className = { styles . partnersTrack } >
81- { duplicatedPartners . map ( ( partner , index ) => (
82- < Link
83- key = { `${ partner . organization } -${ index } ` }
84- href = "/partners"
85- className = { styles . partnerCard }
86- >
87- < div className = { styles . partnerLogoWrapper } >
88- < Image
89- src = { partner . logo }
90- alt = { partner . title }
91- width = { 120 }
92- height = { 80 }
93- className = { styles . partnerLogo }
94- />
95- </ div >
96- </ Link >
97- ) ) }
115+ < div className = { styles . partnersCarouselContainer } >
116+ { /* 第一行 - 向右滚动 */ }
117+ < div className = { styles . partnersCarousel } >
118+ < div
119+ ref = { scrollRef1 }
120+ className = { styles . partnersScroll }
121+ >
122+ < div className = { styles . partnersTrack } >
123+ { firstRowPartners . map ( ( partner , index ) => (
124+ < Link
125+ key = { `row1-${ partner . organization } -${ index } ` }
126+ href = "/partners"
127+ className = { styles . partnerCard }
128+ >
129+ < div className = { styles . partnerLogoWrapper } >
130+ < Image
131+ src = { partner . logo }
132+ alt = { partner . title }
133+ width = { 120 }
134+ height = { 80 }
135+ className = { styles . partnerLogo }
136+ />
137+ </ div >
138+ </ Link >
139+ ) ) }
140+ </ div >
141+ </ div >
142+ </ div >
143+
144+ { /* 第二行 - 向左滚动 */ }
145+ < div className = { styles . partnersCarousel } >
146+ < div
147+ ref = { scrollRef2 }
148+ className = { styles . partnersScroll }
149+ >
150+ < div className = { styles . partnersTrack } >
151+ { secondRowPartners . map ( ( partner , index ) => (
152+ < Link
153+ key = { `row2-${ partner . organization } -${ index } ` }
154+ href = "/partners"
155+ className = { styles . partnerCard }
156+ >
157+ < div className = { styles . partnerLogoWrapper } >
158+ < Image
159+ src = { partner . logo }
160+ alt = { partner . title }
161+ width = { 120 }
162+ height = { 80 }
163+ className = { styles . partnerLogo }
164+ />
165+ </ div >
166+ </ Link >
167+ ) ) }
168+ </ div >
98169 </ div >
99170 </ div >
100171 </ div >
0 commit comments