GSAP 與 Vue、Svelte 及其他框架的整合
何時使用此技能
當你在 Vue(或 Nuxt)、Svelte(或 SvelteKit)或其他具有生命週期(掛載/卸載)的元件框架中撰寫或審查 GSAP 程式碼時應用。對於 React,請專門使用 gsap-react 技能(useGSAP hook, gsap.context())。
相關技能: 補間動畫與時間軸請使用 gsap-core 和 gsap-timeline;滾輪驅動動畫請使用 gsap-scrolltrigger;React 請使用 gsap-react。
原則(所有框架通用)
- 建立 補間動畫和 ScrollTrigger 的時機應在 元件 DOM 可用之後(例如在 onMounted、onMount 中)。
- 在 卸載(或等效)的清理函數中 終止或還原 它們,以確保動畫不會在已分離的節點上執行,並防止資源洩漏。
- 為選擇器設定作用域 至元件根節點,使
.box這類選擇器僅匹配該元件內部的元素,而非頁面的其他部分。
Vue 3(組合式 API)
請參閱 examples/vue/ 中的可執行 Vite + Vue 3 專案,其中示範了這些模式。
使用 onMounted 在元件掛載到 DOM 後執行 GSAP。使用 onUnmounted 進行清理。
import { onMounted, onUnmounted, ref } from "vue";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger); // 每個應用程式註冊一次,例如在 main.js 中
export default {
setup() {
const container = ref(null);
let ctx;
onMounted(() => {
if (!container.value) return;
ctx = gsap.context(() => {
gsap.to(".box", { x: 100, duration: 0.6 });
gsap.from(".item", { autoAlpha: 0, y: 20, stagger: 0.1 });
}, container.value);
});
onUnmounted(() => {
ctx?.revert();
});
return { container };
},
};
- ✅ gsap.context(scope) — 將容器 ref(例如
container.value)作為第二個參數傳遞,如此一來.item等選擇器的作用域就會被限制在該根元素內。在回呼中建立的所有動畫和 ScrollTrigger 都會被追蹤,並在呼叫 ctx.revert() 時被還原。 - ✅ onUnmounted — 始終呼叫 ctx.revert(),以終止補間動畫和 ScrollTrigger,並還原內聯樣式。
Vue 3(<script setup> 語法)
在 <script setup> 和 ref 中使用同樣的概念:
<script setup>
import { onMounted, onUnmounted, ref } from "vue";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
const container = ref(null);
let ctx;
onMounted(() => {
if (!container.value) return;
ctx = gsap.context(() => {
gsap.to(".box", { x: 100 });
gsap.from(".item", { autoAlpha: 0, stagger: 0.1 });
}, container.value);
});
onUnmounted(() => {
ctx?.revert();
});
</script>
<template>
<div ref="container">
<div class="box">Box</div>
<div class="item">Item</div>
</div>
</template>
Nuxt 4
請參閱
examples/nuxt/中的可執行 Nuxt 4 專案,其中包含外掛註冊、延遲載入和 SSR 安全的模式。
使用一個可複用的 composable 來註冊 GSAP 外掛,也可以延遲載入應用程式中不常用的外掛:
// composables/useGSAP.ts
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
const PLUGINS = [
"CSSRulePlugin",
"CustomBounce",
"CustomEase",
"CustomWiggle",
"Draggable",
"DrawSVGPlugin",
"EaselPlugin",
"EasePack",
"Flip",
"GSDevTools",
"InertiaPlugin",
"MorphSVGPlugin",
"MotionPathHelper",
"MotionPathPlugin",
"Observer",
"Physics2DPlugin",
"PhysicsPropsPlugin",
"PixiPlugin",
"ScrambleTextPlugin",
"ScrollSmoother",
"ScrollToPlugin",
"ScrollTrigger",
"SplitText",
"TextPlugin",
] as const;
type Plugins = (typeof PLUGINS)[number];
// 為了動態載入所有 GSAP 外掛
const pluginMap = {
CustomEase: () => import("gsap/CustomEase"),
Draggable: () => import("gsap/Draggable"),
CSSRulePlugin: () => import("gsap/CSSRulePlugin"),
EaselPlugin: () => import("gsap/EaselPlugin"),
EasePack: () => import("gsap/EasePack"),
Flip: () => import("gsap/Flip"),
MotionPathPlugin: () => import("gsap/MotionPathPlugin"),
Observer: () => import("gsap/Observer"),
PixiPlugin: () => import("gsap/PixiPlugin"),
ScrollToPlugin: () => import("gsap/ScrollToPlugin"),
ScrollTrigger: () => import("gsap/ScrollTrigger"),
TextPlugin: () => import("gsap/TextPlugin"),
DrawSVGPlugin: () => import("gsap/DrawSVGPlugin"),
Physics2DPlugin: () => import("gsap/Physics2DPlugin"),
PhysicsPropsPlugin: () => import("gsap/PhysicsPropsPlugin"),
ScrambleTextPlugin: () => import("gsap/ScrambleTextPlugin"),
CustomBounce: () => import("gsap/CustomBounce"),
CustomWiggle: () => import("gsap/CustomWiggle"),
GSDevTools: () => import("gsap/GSDevTools"),
InertiaPlugin: () => import("gsap/InertiaPlugin"),
MorphSVGPlugin: () => import("gsap/MorphSVGPlugin"),
MotionPathHelper: () => import("gsap/MotionPathHelper"),
ScrollSmoother: () => import("gsap/ScrollSmoother"),
SplitText: () => import("gsap/SplitText"),
} as const;
type PluginMap = typeof pluginMap;
type Plugins = keyof PluginMap;
// 解析給定鍵的模組類型,然後選取與鍵同名的具名匯出
// 這允許在您的程式碼編輯器中獲得自動補全的類型定義
type PluginModule<K extends Plugins> = Awaited<ReturnType<PluginMap[K]>>;
type PluginExport<K extends Plugins> = PluginModule<K>[K & keyof PluginModule<K>];
export default function () {
// 在此處註冊您想要的所有 GSAP 外掛
gsap.registerPlugin(ScrollTrigger);
/*
如果您想延遲載入一些應用程式中不常用的外掛
(例如僅在少數元件或單一路由中使用),可以使用此方法
*/
async function lazyLoadPlugin<K extends Plugins>(plugin: K): Promise<PluginExport<K>> {
const loader = pluginMap[plugin];
const m = await loader();
const p = (m as any)[plugin];
gsap.registerPlugin(p);
return p;
}
return {
gsap,
ScrollTrigger,
lazyLoadPlugin,
};
}
透過 useGSAP() 在元件中存取:
const { gsap, ScrollTrigger, lazyLoadPlugin } = useGSAP();
- ✅
useGSAP()提供了類型安全的 gsap 實例和延遲載入方法。 - ✅ 延遲載入任何外掛(SplitText、MorphSVG 等),這些外掛在應用程式中不常用,以減少初始套裝大小。
- ✅ 在元件中使用 gsap.context(scope) 和 onUnmounted → ctx.revert(),與 Vue 3 相同。
Svelte
使用 onMount 在 DOM 準備就緒後執行 GSAP。使用 onMount 回傳的清理函數(或在反應式區塊/元件銷毀時追蹤 context 並清理)來進行還原。Svelte 5 使用不同的生命週期;但相同的原則適用:在「掛載」時建立,在「銷毀」時還原。
<script>
import { onMount } from "svelte";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
let container;
onMount(() => {
if (!container) return;
const ctx = gsap.context(() => {
gsap.to(".box", { x: 100 });
gsap.from(".item", { autoAlpha: 0, stagger: 0.1 });
}, container);
return () => ctx.revert();
});
</script>
<div bind:this={container}>
<div class="box">Box</div>
<div class="item">Item</div>
</div>
- ✅ bind:this={container} — 取得根元素的參考,以便將其傳遞給 gsap.context(scope)。
- ✅ return () => ctx.revert() — Svelte 的 onMount 可以回傳一個清理函數;在此處呼叫 ctx.revert(),以便在元件銷毀時執行清理。
選擇器作用域設定
不要使用可能匹配到目前元件外部元素的全局選擇器。始終將作用域(容器元素或 ref)作為第二個參數傳遞給 gsap.context(callback, scope),以便在回呼內執行的任何選擇器都僅限於該子樹。
- ✅ gsap.context(() => { gsap.to(".box", ...) }, containerRef) —
.box僅在containerRef內部進行搜尋。 - ❌ 在元件中,未經 context 作用域而執行 gsap.to(".box", ...) 可能會影響其他實例或頁面的其餘部分。
ScrollTrigger 清理
當您在補間動畫/時間軸上使用 scrollTrigger 設定或使用 ScrollTrigger.create() 時,會建立 ScrollTrigger 實例。它們被包含在 gsap.context() 中,並在您呼叫 ctx.revert() 時被還原。因此:
- 在與補間動畫相同的 gsap.context() 回呼中建立 ScrollTrigger。
- 在會影響觸發器位置的佈局更改後(例如資料載入後),呼叫 ScrollTrigger.refresh();在 Vue/Svelte 中,這通常發生在 DOM 更新之後(例如 Vue 的 nextTick、Svelte 的 tick,或非同步內容載入後)。
何時建立與終止
| 生命週期 | 動作 |
|---|---|
| 已掛載(Mounted) | 在 gsap.context(scope) 內部建立補間動畫和 ScrollTrigger。 |
| 卸載 / 銷毀(Unmount / Destroy) | 呼叫 ctx.revert(),以便終止該 context 中的所有動畫和 ScrollTrigger,並還原內聯樣式。 |
請勿在元件的 setup 階段或同步的頂層腳本中(即在根元素存在之前)建立 GSAP 動畫。請等待 onMounted / onMount(或等效函數),以便容器 ref 存在於 DOM 中。
禁止事項
- ❌ 在元件掛載之前建立補間動畫或 ScrollTrigger(例如在 setup 中但沒有使用 onMounted);DOM 節點可能尚不存在。
- ❌ 使用沒有作用域的選擇器字串(將容器作為第二個參數傳遞給 gsap.context()),以免選擇器匹配到元件外部的元素。
- ❌ 跳過清理;始終在 onUnmounted / onMount 的回傳值中呼叫 ctx.revert(),以便在元件銷毀時終止動畫和 ScrollTrigger。
- ❌ 在每次渲染都會執行的元件主體內註冊外掛(這不會造成傷害,只是浪費資源);請在應用程式層級註冊一次。
了解更多
- 針對 React 的 gsap-react 技能(useGSAP, contextSafe)。