iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0
Modern Web

前端互動視覺技術實作 LAB系列 第 6

Day6|GSAP 入門(5)Context 管理與高頻更新動畫

  • 分享至 

  • xImage
  •  

前幾天我們從 GSAP 的 Tween、Timeline 一路講到 ScrollTrigger,動畫已經可以跟著按鈕或捲動播放。
但實際把動畫放進 Vue 元件並產生互動後,還必須考慮兩件事,第一個就是我們再 day 1 有提過的「清除動畫」,第二的就是進行互動時,像是游標位置這種隨時再進行的互動,需要做高頻更新。
今天我們就來整理 GSAP 動畫的管理方式。第一個實驗可以直接看到 context.kill()context.revert() 留下的畫面差異;第二個實驗則能切換兩種游標的跟隨方式 quickTo()quickSetter()

老樣子,我們可以搭配 demo 來實際操作~ 👉🏿 demo連結

用 gsap.context() 把多個動畫集中管理

gsap.context() 可以把 callback 內建立的 GSAP 動畫歸在同一組管理:

context = gsap.context(() => {
  const samples = gsap.utils.toArray(".day-06-sample");

  timeline = gsap.timeline({
    paused: true,
    repeat: -1,
    yoyo: true,
    defaults: { duration: 1.15, ease: "power2.inOut" },
  });

  timeline
    .to(samples[0], { x: 76, rotation: 180, backgroundColor: "#c97958" }, 0)
    .to(samples[1], { y: -38, scale: 1.35, backgroundColor: "#b38a4a" }, 0.12)
    .to(samples[2], { x: -70, rotation: -135, scale: 0.76 }, 0.24);
}, stageRef);

最外層先把 gsap.context() 回傳的物件存進 context。後續就可以對這個範圍內的動畫進行操作

callback 一執行,gsap.utils.toArray(".day-06-sample") 會取得舞台裡的三個圖形,並依照 DOM 順序放進 samples。所以 samples[0]samples[1]samples[2],分別對應左到右的三個幾何樣本。

  • paused: true 讓動畫先停著,等使用者按下「同步開始」才播放
  • repeat: -1 代表無限重複,如果是正整數就是直接控制重播次數
  • yoyo: true 則讓每一輪來回播放
  • 三段 Tween 共用相同的時間與 easing,因此放進 defaults,不用每一段都重寫一次。
  • stageRef 是傳給 gsap.context() 的 DOM 容器,用來限制 selector 的搜尋範圍;因此 Context 裡的 .day-06-sample 只會選到該容器內的圖形,不會影響頁面上其他同名元素。

Timeline 與裡面的 Tween 都是在 callback 中建立,因此會被這個 context 一起管理。後面不必逐一找出三個 Tween,只要操作 context 就能處理整組動畫。接下來,我們來看看如果要利用 context 一次清除這些動畫,可以如何操作?

context.kill() 和 context.revert() 差在哪裡?

https://ithelp.ithome.com.tw/upload/images/20260825/201831496TME6uGyyu.png
兩者都會清除 context 收集的動畫,差別在於 context.kill() 會終止動畫,但保留 GSAP 已經寫進元素的 inline styles ,位移、旋轉和顏色都還留著,只是動畫不會再繼續;context.revert() 同樣會終止動畫,但會移除動畫產生的 inline styles,讓元素回到執行動畫前的狀態

分別按下左右的按鈕,左側執行 context.kill(),右側執行 context.revert()。左側的三個圖形會停在操作當下;右側則直接回到 CSS 原本設定的位置與顏色。

但要注意的是,context 的用途是集中清理與限制 selector 範圍,不是拿來控制播放。一般的播放、暫停或倒轉,還是交給 Tween 和 Timeline。

在 Vue 元件卸載時,我通常會使用 context.revert() 進行清理,讓 GSAP 還原動畫造成的狀態變更,避免在較複雜的生命週期情境下,kill() 保留下來的狀態影響元件再次掛載時的動畫起點。

quickTo() 高頻更新

接著 GSAP 的最後,我想補充另一個實用的函式quickTo(),會建立可重複使用的 Tween 來快速更新單一屬性,特別適合滑鼠移動、游標追蹤等高頻事件。

舉例來說,若要讓物件持續跟隨游標移動,最暴力的做法就是反覆呼叫 gsap.to(),但每次事件觸發都會建立新的 Tween,造成不必要的負載;使用 quickTo() 則能先建立可重複使用的更新函式,事件觸發時只需傳入新值即可。

quickTo() 先替 x 和 y 各建立一個控制函式:

const xTo = gsap.quickTo(follower, "x", {
  duration: 0.45,
  ease: "power3.out",
});

const yTo = gsap.quickTo(follower, "y", {
  duration: 0.45,
  ease: "power3.out",
});

Pointer 移動時,把算好的座標交給它們:

function handlePointerMove(event) {
  const { x, y } = getPosition(event);
  xTo(x);
  yTo(y);
}

它會重用同一個 Tween,把終點更新成最新座標,並依照設定的 duration 和 ease 追過去。

與 quickSetter() 有甚麼不一樣?

最直接的說,quickSetter() 沒有 Tween,同樣也是高頻更新,但物件隨時保持在 Pointer 位置上,沒辦法做延遲跟隨 (追趕) 的效果。範例如下:

const setX = gsap.quickSetter(follower, "x", "px");
const setY = gsap.quickSetter(follower, "y", "px");

function handlePointerMove(event) {
  const { x, y } = getPosition(event);
  setX(x);
  setY(y);
}

第三個參數是單位。這裡傳入 "px",後續只需要提供數字,不會建立補間過程,收到新值就立刻寫入。從 demo 就可以明顯觀察到,quickTo() 看起來比較柔順,quickSetter() 則緊貼輸入位置。

貼心提醒!這類互動最好更新 xy 等 transform 屬性,不要反覆修改 lefttop。Demo 也會依舞台的實際尺寸限制座標,避免 Follower 跑出容器。

小結

回顧一下今天的內容:gsap.context() 能幫我們收集動畫並限制 selector 的作用範圍;如果需要保留停止當下的畫面,可以用 context.kill(),而在元件卸載或需要恢復初始狀態時,則使用 context.revert()

另外,針對 Pointer 這類高頻輸入,不需要一直重複建立 gsap.to()——需要補間動畫時選擇 quickTo(),只想即時寫入狀態就用 quickSetter()。 結合前幾天學到的技巧,就能做出非常多有趣的互動了!

GSAP 還有太多值得探索的玩法,以上是我認為非常關鍵的基礎,最核心的部分就先介紹到這邊。明天開始,我們將開始講解 Canvas!


上一篇
Day 5|GSAP 入門(4)用 ScrollTrigger 打造滾動敘事
下一篇
Day 7|認識瀏覽器的圖形技術
系列文
前端互動視覺技術實作 LAB19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言