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:
@@ -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(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user