fix: 修复所有板块 pin 滚动空白间隙 + 服务卡片适配屏幕

🐛 问题1: 滚动到下一个内容时有空白区
根因: 时间线动画之间有间隙(动画 duration < 步骤间距)
修复: 所有板块改用 cursor 模式,每个步骤精确衔接,无空白

🐛 问题2: 服务卡片太大,一屏显示不全
根因: 卡片高度固定 h-[380px],不适配小屏幕
修复: 改用 clamp(260px, 38vh, 400px) 自适应屏幕高度

🔧 修复的 6 个板块:
1. HomeTestimonials - 淡入淡出切换无间隙
2. HomeServices - 卡片聚焦无间隙 + 自适应高度
3. HomeAchievements - 数字展示无间隙
4. HomeTechStack - 球体旋转无间隙
5. HomeProcess - 步骤展示 + 横向滚动无间隙
6. HomeUpdates - 卡片分批出现无间隙

📐 cursor 模式:
每一步动画 duration 正好等于步骤间距,
动画结束 = 下一步开始,完美衔接

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
陈春
2026-06-03 20:03:36 +08:00
parent 02323fd426
commit e94f7d92e9
6 changed files with 80 additions and 66 deletions
+19 -20
View File
@@ -223,45 +223,44 @@ onMounted(async () => {
gsap.set(step, { autoAlpha: 0, y: 60, scale: 0.85 })
})
// 统一时间线
// 统一时间线:无空白
const tl = gsap.timeline()
let cursor = 0
// 第一屏:标题入场
tl.to(headerRef.value, { autoAlpha: 1, y: 0, duration: 0.8, ease: 'power3.out' }, 0)
tl.to(headerRef.value, { autoAlpha: 1, y: 0, duration: 0.8, ease: 'power3.out' }, cursor)
cursor += 1
// 连接线绘制
// 第二屏:连接线绘制 + 所有步骤卡片出现
if (lineRef.value && linePathRef.value) {
const pathLength = linePathRef.value.getTotalLength()
gsap.set(linePathRef.value, { strokeDasharray: pathLength, strokeDashoffset: pathLength })
tl.to(lineRef.value, { autoAlpha: 1, duration: 0.3 }, 0.5)
tl.to(linePathRef.value, { strokeDashoffset: 0, duration: 2, ease: 'power2.inOut' }, 0.5)
tl.to(lineRef.value, { autoAlpha: 1, duration: 0.3 }, cursor)
tl.to(linePathRef.value, { strokeDashoffset: 0, duration: 1.5, ease: 'power2.inOut' }, cursor)
}
stepElements.value.forEach((step, index) => {
if (!step) return
tl.to(step, {
autoAlpha: 1, y: 0, scale: 1,
duration: 0.6, ease: 'back.out(1.5)',
}, cursor + index * 0.1)
})
cursor += 1
// 横向滚动:步骤卡片逐个出现
// 第三屏起:横向滚动
if (scrollContainerRef.value) {
const container = scrollContainerRef.value.querySelector('.flex')
if (container) {
const scrollWidth = container.scrollWidth - window.innerWidth
// 逐个展示步骤
stepElements.value.forEach((step, index) => {
if (!step) return
tl.to(step, {
autoAlpha: 1, y: 0, scale: 1,
duration: 0.6, ease: 'back.out(1.5)',
}, 1 + index * 0.3)
})
// 横向滚动
tl.to(container, { x: -scrollWidth, duration: 3, ease: 'none' }, 1)
tl.to(container, { x: -scrollWidth, duration: 2, ease: 'none' }, cursor)
cursor += 2
}
}
const totalSteps = stepElements.value.length || 6
ScrollTrigger.create({
trigger: rootRef.value,
start: 'top top',
end: () => `+=${(totalSteps + 2) * window.innerHeight}`,
end: () => `+=${cursor * window.innerHeight}`,
pin: true,
scrub: 0.5,
anticipatePin: 1,