feat: 为首页新增板块添加 ScrollTrigger pin 滚动效果

 新增 pin 效果(板块固定,内容随滚动切换):

1. HomeTestimonials - 客户评价
   - 固定板块,滚动自动切换卡片
   - 每屏切换一张评价卡片

2. HomeTechStack - 技术栈
   - 固定板块,3D 球体自动旋转一圈
   - 滚动控制旋转进度

3. HomeProcess - 创意流程
   - 固定板块,横向滚动浏览所有步骤
   - 6 个步骤依次展示

4. HomeServices - 服务能力
   - 固定板块,逐张卡片聚焦展示
   - 聚焦卡片放大,其他缩小变暗
   - 所有卡片飞入归位后逐个聚焦

5. HomeAchievements - 数字成就
   - 固定板块,逐个成就项展示
   - 每个数字滚动计数动画触发

6. HomeUpdates - 最新动态
   - 固定板块,逐批展示卡片
   - 分批出现,每批 3 个卡片

🎯 效果:
- 滚动到板块时自动固定(pin)
- 内部元素随滚动依次展示
- 所有内部元素展示完毕后才继续下一个板块
- 每个板块独特的 pin 动画效果

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
陈春
2026-06-03 19:49:18 +08:00
parent 89c4c4c7b5
commit bb0020b406
6 changed files with 208 additions and 76 deletions
+34 -21
View File
@@ -180,34 +180,47 @@ onMounted(async () => {
}
)
// 卡片错开入场 - 每列不同速度
cardElements.value.forEach((card, index) => {
// Pin 效果:固定板块,逐行展示卡片
const totalCards = updates.length
const timeline = gsap.timeline()
// 初始隐藏所有卡片
cardElements.value.forEach((card) => {
if (!card) return
gsap.set(card, { autoAlpha: 0, y: 60, scale: 0.9 })
})
// 根据列位置计算延迟
const columnDelay = (index % 3) * 0.1
const rowDelay = Math.floor(index / 3) * 0.15
// 分批展示:每批展示一行(按顺序,每行 2-3 个)
const batchSize = 3
const batches = Math.ceil(totalCards / batchSize)
gsap.fromTo(card,
{
autoAlpha: 0,
y: 80,
scale: 0.9
},
{
scrollTrigger: {
trigger: card,
start: 'top 85%',
toggleActions: 'play none none reverse'
},
for (let batch = 0; batch < batches; batch++) {
timeline.addLabel(`batch-${batch}`)
const start = batch * batchSize
const end = Math.min(start + batchSize, totalCards)
for (let i = start; i < end; i++) {
if (!cardElements.value[i]) continue
timeline.to(cardElements.value[i], {
autoAlpha: 1,
y: 0,
scale: 1,
duration: 0.8,
delay: columnDelay + rowDelay,
ease: 'power3.out'
}
)
ease: 'power3.out',
}, `batch-${batch}+=${(i - start) * 0.15}`)
}
}
ScrollTrigger.create({
trigger: rootRef.value,
start: 'top top',
end: () => `+=${batches * window.innerHeight}`,
pin: true,
scrub: true,
anticipatePin: 1,
animation: timeline,
})
}, rootRef.value)
})