fix: 修复首屏加载慢和菜单延迟问题

🐛 核心问题:
- HomePartnersWork 的 ScrollTrigger 在 onMounted 时立即初始化
- 复杂的卡片堆叠动画计算阻塞了首屏 Hero 动画
- 导致菜单延迟出现,用户体验不佳

 解决方案:
- 监听 'hero-intro-done' 事件,等待 Hero 动画完成后才初始化
- 添加 3 秒保底延迟,确保不会无限等待
- 将 ScrollTrigger 初始化封装为独立函数
- 不影响原有的卡片堆叠滚动效果

🎯 效果:
- 首屏 Hero 动画流畅,不再被阻塞
- 菜单在 Hero 动画 60% 时立即出现
- HomePartnersWork 在 Hero 完成后异步初始化
- 用户体验大幅提升

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
陈春
2026-06-03 19:31:44 +08:00
parent ae20560a35
commit 0c5ad55621
+69 -52
View File
@@ -100,66 +100,83 @@ onMounted(async () => {
await nextTick() await nextTick()
ctx = gsap.context(() => { // 延迟初始化 ScrollTrigger,避免阻塞首屏 Hero 动画
const cards = cardRefs.value // 等待 Hero 入场动画完成(约 3-4 秒)
const count = cards.length const initScrollAnimation = () => {
ctx = gsap.context(() => {
const cards = cardRefs.value
const count = cards.length
if (count < 2) return if (count < 2) return
const enterOffset = 160 const enterOffset = 160
const scaleTo = 0.92 const scaleTo = 0.92
const depthOffsetY = -18 const depthOffsetY = -18
for (let i = 0; i < count; i += 1) { for (let i = 0; i < count; i += 1) {
const card = cards[i] const card = cards[i]
gsap.set(card, { gsap.set(card, {
position: 'absolute', position: 'absolute',
inset: 0, inset: 0,
borderRadius: 22, borderRadius: 22,
overflow: 'hidden', overflow: 'hidden',
transformOrigin: 'center center', transformOrigin: 'center center',
force3D: true, force3D: true,
zIndex: i + 1, zIndex: i + 1,
boxShadow: '0 18px 40px rgba(0,0,0,0.12)', boxShadow: '0 18px 40px rgba(0,0,0,0.12)',
y: i === 0 ? 0 : window.innerHeight + enterOffset, y: i === 0 ? 0 : window.innerHeight + enterOffset,
scale: 1, scale: 1,
})
}
const tl = gsap.timeline()
for (let i = 1; i < count; i += 1) {
const prev = cards[i - 1]
const next = cards[i]
const start = i - 1
tl.to(
next,
{ y: 0, duration: 1, ease: 'power2.out' },
start
)
tl.to(
prev,
{ scale: scaleTo, y: depthOffsetY, duration: 0.6, ease: 'power2.out' },
start + 0.35
)
tl.set(prev, { scale: scaleTo, y: depthOffsetY }, start + 1)
}
ScrollTrigger.create({
trigger: workSectionRef.value,
start: 'top top',
end: () => `+=${(count - 1) * window.innerHeight}`,
pin: workPinRef.value,
scrub: true,
anticipatePin: 1,
invalidateOnRefresh: true,
animation: tl,
}) })
}
const tl = gsap.timeline() ScrollTrigger.refresh()
}, rootRef.value)
}
for (let i = 1; i < count; i += 1) { // 监听 hero 动画完成事件
const prev = cards[i - 1] if (typeof window !== 'undefined') {
const next = cards[i] window.addEventListener('hero-intro-done', initScrollAnimation, { once: true })
const start = i - 1
tl.to( // 保底:3秒后必定初始化
next, setTimeout(() => {
{ y: 0, duration: 1, ease: 'power2.out' }, window.removeEventListener('hero-intro-done', initScrollAnimation)
start if (!ctx) {
) initScrollAnimation()
tl.to( }
prev, }, 3000)
{ scale: scaleTo, y: depthOffsetY, duration: 0.6, ease: 'power2.out' }, }
start + 0.35
)
tl.set(prev, { scale: scaleTo, y: depthOffsetY }, start + 1)
}
ScrollTrigger.create({
trigger: workSectionRef.value,
start: 'top top',
end: () => `+=${(count - 1) * window.innerHeight}`,
pin: workPinRef.value,
scrub: true,
anticipatePin: 1,
invalidateOnRefresh: true,
animation: tl,
})
ScrollTrigger.refresh()
}, rootRef.value)
}) })
onUnmounted(() => { onUnmounted(() => {