嗨咿,我是 illumi,昨天我們用GSAP Timeline + ScrollTrigger 來用滑鼠播放動畫,但播到一半我想控制其他東西怎麼辦?
外層一個大範圍的沈浸式動畫滑到一半時,要「暫停」大動畫,接著讓內層小動畫(例如 Carousel、遊戲區塊)接手控制。
import ChildAnime from "你的路徑";
//外層動畫
<div ref={mainRef}>
//其他元素
<ChildAnime isCarouselMode={isCarouselMode}/>
</div>
首先,我們用一個大動畫來主宰整個頁面的沉浸感。這裡我直接用 mainRef
來當外層元素。
import { useRef, useState, useEffect } from "react";
const mainRef = useRef<HTMLDivElement>(null);
const [isCarouselMode, setIsCarouselMode] = useState(false);
useGSAP(() => {
if (!mainRef.current) return;
const tl = gsap.timeline();
tl.to(mainRef.current, {
keyframes: [
{ scale: 1, opacity: 0 },
{ scale: 1, opacity: 1 },
{ scale: 10, opacity: 1 },
{ scale: 10, opacity: 1 },
{ scale: 5, opacity: 1 },
],
duration: 1,
scrollTrigger: {
trigger: mainRef.current,
start: "top top",
end: "+=1000%",
scrub: 1,
pin: true,
pinSpacing: true,
onUpdate: (self) => {
const progress = self.progress;
if (progress >= 0.4 && progress <= 0.6) {
setIsCarouselMode(true); // 暫停大動畫,交給內層
} else {
setIsCarouselMode(false); // 外層動畫繼續跑
}
},
},
});
});
mainRef
,所以動畫跟這個元素掛鉤。在外層進度進到 0.4 到 0.6 之間時,代表大動畫暫停,我們就啟用內層動畫。
if (progress >= 0.4 && progress <= 0.6) {
setIsCarouselMode(true);
} else {
setIsCarouselMode(false);
}
這樣一來,我們就能用 isCarouselMode
這個狀態去決定內層要不要動。
當外層暫停後,我們希望內層(例如輪播、遊戲機)接手。這裡我用一個 Carousel 例子。
useGSAP(() => {
if (!isCarouselMode || !carouselRef.current || isTriggered) return;
setIsTriggered(true);
// 內層淡入效果
gsap.to(".title-icon", {
opacity: 1,
duration: 1,
ease: "power1.inOut",
});
// 內層捲動控制
gsap.to(".slide", {
scrollTrigger: {
trigger: carouselRef.current,
start: "top top",
end: "+=250%",
scrub: 1,
onUpdate: (self) => {
setSlideIndex(Math.max(0, Math.floor(self.progress * 5) - 1));
},
},
});
}, { dependencies: [isCarouselMode] });
<div ref={carouselRef}>
內層動畫
</div>
slideIndex
,讓 Carousel 滑到不同頁。GSAP ScrollTrigger 的邏輯是:
內層動畫完全跟隨外層的「頁面滾動進度」。
→ 使用者滾動多少,動畫就走多少,progress
會從 0 → 1 線性對應。
Swiper / shadcn 的邏輯是:
它們是 手勢 / 按鈕驅動,每次都是一頁一頁切換,並不是「進度條」驅動。
→ 這些套件沒辦法被 ScrollTrigger 綁定到「滾動百分比」上。
用 Swiper,它的翻頁行為和 ScrollTrigger 的進度不同步,外層停在 0.45 進度時,Swiper 可能卡在第 2 頁,但 GSAP 需要一個「數字進度」去算 slide index。這兩個系統會打架。
外層在等 scroll progress
,內層卻在搶滑動事件,這樣兩個動畫會互相搶控制權。
耶依~醬就可以做出來了! 我們明天再見~