GreenSock Animation Platform (GSAP) 是一個業界知名的動畫庫,它被1100多萬個網站使用,有超過50%的獲獎的網站都是用了它。不管是在原生環境中,還是任意的框架中,你可以使用GSAP去讓非常多的東西動起來。不管你是想要去讓UI介面產生互動動畫,還是SVG圖形產生動畫,甚至是Threejs還是React元件,GSAP都可以輕鬆搞定!
讓我們先讓一個class為'box'的HTML元素動起來
gsap.to(".box",{x:200})
有四種Tween的動畫方式
gsap.to() 這是一種最常用的動畫,就是讓元素從初始狀態變化到目標狀態。
gsap.from() 有點像to方法的逆向變化,就是讓元素從目標狀態變化到初始狀態。
gsap.fromTo() 需要自己定義兩個狀態的資料,然後從前一個變化到後一個。
gsap.set() 直接設定成想要的狀態,沒有任何過度與動畫效果。本質上就是duration為0的 .to 方法
接下來我們需要去告訴GSAP去讓什麼元素變化。GSAP在底層實際上是使用了document.querySelector( )去選擇元素,所以你可以用任何css選擇器進行元素的選擇。或者你也可以直接傳入一個DOM元素或者一個陣列
// 使用類名或者id名,其實css選擇器都可以
gsap.to(".box", { x: 200 });
// 複雜一些的css選擇器
gsap.to("section > .box", { x: 200 });
// 一個變數,其實是把獲取到的DOM元素直接傳進去
let box = document.querySelector(".box");
gsap.to(box, { x: 200 })
// 可以把dom元素放到陣列裡面一起傳入
let square = document.querySelector(".square");
let circle = document.querySelector(".circle");
gsap.to([square, circle], { x: 200 })
這個物件包含著所有動畫變化相關的資訊。你可以設定任意的你想要發生變化的屬性和值,或者一些特殊的會影響動畫過程的一些屬性,比如duration(動畫時長),onComplete(動畫完成時觸發事件)或者repeat(動畫重複的次數)
gsap.to(target, {
// 傳入這樣一個物件
// 這裡麵包含了需要進行變化的各種樣式屬性
x: 200,
rotation: 360,
// 以及變化過程的屬性設定
duration: 2,
})
GSAP | CSS | 作用 |
---|---|---|
x:100 | transform:translateX(100px) | 水平移動 (px或者svg單位) |
y:100 | transform:translateY(100px) | 垂直移動 (px或者svg單位) |
xPercent:-50% | transform:translateX(-50%) | 橫向移動 (元素本身寬度的百分比) |
yPercent:-50% | transform:translateY(-50%) | 垂直移動 (元素本身高度的百分比) |
rotation:360 | transform:rotate(360deg) | 旋轉多少度 |
scale:2 | transform:scale(2,2) | 元素整體放大或縮小 |
skewX:45 | transform:skewX(45deg) | 元素傾斜 |
transformOrigin:"0% 100%" | transform-origin: 0% 100%; | 設定旋轉中心點。這裡設定的旋轉中心點是元素左下角 |
屬性 | 作用 |
---|---|
duration | 動畫變化的時長(秒)預設是0.5 |
delay | 動畫變化開始前的延遲時長(秒),預設是0.5 |
repeat | 動畫的重複次數 設定為-1表示無數次 |
repeatDelay | 重複延遲,重複之間的秒 |
repeatRefresh | 重複重新整理 |
yoyo | 如果設定為ture,那麼動畫會在執行完之後再反向執行一次,就像悠悠球的效果。注意( repeat得設定大於1或者為-1才能看到效果。) 預設是false |
stagger | 是一個時間的設定(秒),如果有多個元素同時要被驅動,那麼當這個屬性設定了時間的值之後,元素們會被依次逐個驅動,間隔時長就是這個屬性設定的時長 |
ease | 動畫過渡的運動曲線的設定,預設是"power1.out" |
onComplete | 動畫結束時執行的回撥函數 |
onStart | 動畫開始時呼叫 |
onUpdata | 每次動畫更新時呼叫(在動畫處於活動狀態時每幀呼叫) |
onRepeat | 每次動畫重複時呼叫一次。 |
onReverseComplete | 動畫反轉後再次到達其起點時呼叫 |
時間線能讓我們建立非常容易調節的、很靈活的順序動畫效果。下面就是一個簡單的包含著三個tween動畫的timeline範例效果。預設情況下,這些動畫是依次新增的,他們在變化的時候也是依次執行,而且是一個執行完之後再下一個執行
// 建立一個Timeline型別的範例
let tl = gsap.timeline()
// 把tween動畫新增到timeline範例上,注意我們在用的是tl.to 而不是gsap.to
tl.to(".green", { x: 600, duration: 2 });
tl.to(".purple", { x: 600, duration: 1 });
tl.to(".orange", { x: 600, duration: 1 });
但是,如果我們想要在動畫之間加一個停頓或者說間隔改怎麼辦呢?
let tl = gsap.timeline()
tl.to(".green", { x: 600, duration: 2 });
tl.to(".purple", { x: 600, duration: 1, delay: 1 }); // 在這裡延遲1秒執行
tl.to(".orange", { x: 600, duration: 1 });
有一個方式就是我們可以給某個tween動畫在啟動前提新增一個delay。但是這樣的話,一點都不靈活。又或者,如果我們想要實現動畫之間在時間上重疊,又或者幾個動畫同時啟動,這些該怎麼實現呢?
如果你發現你寫了好幾個Tween動畫,來讓某個元素變化到一個目標狀態,那麼可能你是需要使用關鍵幀(KeyFrames)的方式來做了。關鍵幀動畫能讓元素的屬性變化分段進行,同時又能保持程式碼的清爽整潔。
比如下面這個程式碼,同樣一個變化效果,我們先用timeline的方式來實現,然後再用關鍵幀的方式來實現,顯然關鍵幀的方式看起來簡潔多了
// timeline
let tl = gsap.timeline();
tl.to(".box", { x: 100 })
.to(".box", { y: 100 })
.to(".box", { x: 0 })
.to(".box", { y: 0 });
// 用陣列的方式
gsap.to(".box", {
keyframes: {
x: [0, 100, 100, 0, 0],
y: [0, 0, 100, 100, 0],
ease: "power1.inOut"
},
duration: 2
});
這個引數能幫我們方便的實現執行順序和執行時間點的精確控制
let tl = gsap.timeline();
// 綠色方塊會在整個時間線開始1秒後進行移動
tl.to(".green", { x: 600, duration: 1 }, 1);
// 紫色方塊會和之前一個新增的動畫同時開始運動
tl.to(".purple", { x: 600, duration: 1 }, "<");
// 橘色方塊會在之前所有動畫都結束一秒後再開始運動
tl.to(".orange", { x: 600, duration: 1 }, "+=1");
注意,+= -= 這種是針對整個時間線動畫來說的,而 >(結尾) 和 <(開頭) 是針對前一個新增的動畫來說的
基於百分比的複雜字串形式。如果字首是'+='或者'-=',那麼表示的百分比是基於整個時間線已經新增的所有動畫的總時長的。如果字首是'<'或者'>',那麼這個是基於前一個新增動畫的時長的。注意,總時長是包含了重複或者yoyo效果的時長的
let tl = gsap.timeline();
tl.to(element, 1, {x: 200})
// 新增到整個時間線結束時間點後1秒,相當於是有了1秒的間隔
.to(element, {duration: 1, y: 200}, "+=1")
// 新增到整個時間線結束的時間點的前0.5秒,也就是有0.5秒的時間是和時間線原本的動畫重疊
.to(element, {duration: 1, rotation: 360}, "-=0.5")
// 從時間線動畫開頭時間點往後6秒的時間點
.to(element, {duration: 1, scale: 4}, 6);
// 在時間線2秒的時間點新增一個標記
tl.add("scene1", 2)
// 把動畫提新增到 scene1 這個標記所在的時間點
.to(element, {duration: 4, x: 200}, "scene1")
// 把動畫新增到 scene1 這個標記點往後3秒的時間點
.to(element, {duration: 1, opacity: 0}, "scene1+=3");
比較常見的就是比如說我們想要點選某個按鈕或有了某個互動行為之後才會讓元素進行動畫效果。那麼控制動畫的幾個方法呢可以幫我們實現這個需求,在tween和timeline上都有這些方法,play,pause,reverse或者是加速變化
// 通過一個變數儲存對Tween或者Timeline範例的參照
let tween = gsap.to("#logo", {duration: 1, x: 100});
tween.isActive() // 如果當前正在製作動畫,則為 true
// 播放
tween.play();
// 暫停
tween.pause();
// 恢復(繼續)
tween.resume();
// 反向變化
tween.reverse();
// 直接切換到整個動畫變化時長的0.5秒的時間點的狀態
tween.seek(0.5);
// 直接切換到整個變化過程的1/4的節點的狀態
tween.progress(0.25);
// 讓運動減速到0.5倍
tween.timeScale(0.5);
// 讓變化加速到原來的2倍
tween.timeScale(2);
// 直接銷燬tween範例,讓垃圾回收機制可以處理該範例所佔用的記憶體
tween.kill();
引入方式
<!-- CDN -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js"></script>
// ES Modules
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
範例
ScrollTrigger.create({
start:"top top",
end:"+=600",
trigger:".body", //捲動到視口元素
scrub:true, //將動畫進度直接連結到捲動觸發器的進度
pin:true, // 固定自身元素元素
// markers:true, //開啟標註功能
animation:gsap.timeline()
.to(".green", { x: 300, opacity: 1, rotation: -360, duration: 2 })
.to(".purple", { x:0, opacity: 1, rotation: -360, duration: 2 },"-=2")
.to(".blue", { x: -300, opacity: 1, rotation: -360, duration: 2 },"-=2")
})
常用屬性
屬性 | 型別 | 說明 |
---|---|---|
start | 數位 | 方位名詞 | 捲動觸發器開啟捲動的位置(數位,以畫素為單位)[觸發器][卷軸] |
end | 數位 | 方位名詞 | 捲動觸發器結束捲動的位置(數位,以畫素為單位)[觸發器][卷軸] |
trigger | Element | undefined | 觸發元素 |
animation | Tween | Timeline | undefined | 與捲動觸發器範例關聯的補間或時間線 |
scrub | 布林 | 數位 | 布林值【 scrub:true 將動畫進度直接連結到捲動觸發器的進度 】 數位 - 播放頭「趕上」所需的時間(以秒為單位),因此0將導致動畫的播放頭需要0.5秒才能趕上卷軸的位置,它非常適合平滑事件 |
toggleClass | 字串 | 物件 | 當ScrollTrigger切換活動/非活動時,向一個元素(或多個元素)新增/刪除類 |
markers | true | 開啟標註功能(更好看出捲動開始以及截止的地方 注意:不要在生產環境使用) |
scroller | Element | window | 與捲動觸發器關聯的捲動元素(或視窗)。它是卷軸連線到捲動觸發器的東西。預設是視窗(視口) |
pin | Element | undefined | 固定元素。pin:true 就是自身元素,pin:'.xxx' 就是指定元素 |
對視窗(如執行 window.scrollTo(x, y) )或 DOM 元素(如執行 myDiv.scrollTop = y; myDiv.scrollLeft = x; )的捲動位置進行動畫處理。
注意:如果您想製作捲動驅動的動畫,其中某些內容在某些卷軸位置被觸發,請使用 ScrollTrigger 外掛。
| 在 CSS 中使用 scroll-behavior: smooth 會導致衝突
引入方式
<!-- CDN -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollToPlugin.min.js"></script>
// ES Modules
import { gsap } from "gsap";
import { ScrollToPlugin } from "gsap/ScrollToPlugin";
gsap.registerPlugin(ScrollToPlugin);
// 要將視窗捲動到特定位置,請使用視窗作為補間的目標,如下所示:
gsap.to(window, {duration: 2, scrollTo: "#someID"});