统一字体 响应式 调整
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react'
|
||||
import CertificateCard, { certificates } from './CertificateCard'
|
||||
|
||||
export default function CertificateCarousel() {
|
||||
const [active, setActive] = useState(2) // 从中间开始 (ISO 45001)
|
||||
const [isMobile, setIsMobile] = useState(false)
|
||||
|
||||
// 检测是否为移动端
|
||||
useEffect(() => {
|
||||
const check = () => setIsMobile(window.innerWidth < 768)
|
||||
check()
|
||||
window.addEventListener('resize', check)
|
||||
return () => window.removeEventListener('resize', check)
|
||||
}, [])
|
||||
|
||||
const next = useCallback(() => {
|
||||
setActive(prev => (prev + 1) % certificates.length)
|
||||
}, [])
|
||||
|
||||
// 自动轮播
|
||||
useEffect(() => {
|
||||
const timer = setInterval(next, 3000)
|
||||
return () => clearInterval(timer)
|
||||
}, [next])
|
||||
|
||||
const goTo = (index) => setActive(index)
|
||||
|
||||
// 响应式参数
|
||||
const containerHeight = isMobile ? 'h-[360px]' : 'h-[600px]'
|
||||
const translateXBase = isMobile ? 140 : 260
|
||||
const scaleCenter = 1.0
|
||||
const scaleNear = isMobile ? 0.8 : 0.7
|
||||
const scaleFar = isMobile ? 0.5 : 0.4
|
||||
|
||||
return (
|
||||
<div className="relative max-w-4xl mx-auto">
|
||||
{/* 证书展示区 */}
|
||||
<div className={`relative ${containerHeight} flex items-center justify-center`}>
|
||||
{certificates.map((cert, i) => {
|
||||
let offset = i - active
|
||||
|
||||
// 循环环绕:取最短路径
|
||||
if (offset > 2) offset = offset - certificates.length
|
||||
if (offset < -2) offset = offset + certificates.length
|
||||
|
||||
const absOffset = Math.abs(offset)
|
||||
|
||||
let scale = scaleCenter
|
||||
if (absOffset === 1) scale = scaleNear
|
||||
if (absOffset >= 2) scale = scaleFar
|
||||
|
||||
let opacity = 1
|
||||
if (absOffset === 1) opacity = 0.6
|
||||
if (absOffset >= 2) opacity = 0
|
||||
|
||||
let translateX = offset * translateXBase
|
||||
|
||||
let zIndex = 10 - absOffset
|
||||
|
||||
return (
|
||||
<div
|
||||
key={cert.id}
|
||||
className="absolute transition-all duration-500 ease-in-out cursor-pointer"
|
||||
style={{
|
||||
transform: `translateX(${translateX}px) scale(${scale})`,
|
||||
opacity,
|
||||
zIndex,
|
||||
filter: absOffset >= 2 ? 'blur(2px)' : 'none',
|
||||
}}
|
||||
onClick={() => goTo(i)}
|
||||
>
|
||||
<CertificateCard certificate={cert} index={i} scale={isMobile ? 0.7 : 1} />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* 底部指示点 */}
|
||||
<div className="flex justify-center gap-2 mt-4">
|
||||
{certificates.map((cert, i) => (
|
||||
<button
|
||||
key={cert.id}
|
||||
onClick={() => goTo(i)}
|
||||
className={`w-2 h-2 rounded-full transition-all duration-300 ${
|
||||
i === active
|
||||
? 'bg-[#004ec4] w-6'
|
||||
: 'bg-[#004ec4]/30 hover:bg-[#004ec4]/50'
|
||||
}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user