Learn GSAP-1
前言 Preface
最近刷职位, 发现不少需要酷炫吊炸天landing page需求的, 此blog作为学习笔记, 学习一下当今天下第一的GSAP.
Recently, while searching job postings, I noticed that many positions require creating luxury and cool landing pages. This blog serves as my study notes as I learn the world's top animation library, GSAP.
这里直接引入gsap@3.15, 所有demo都可以编辑预览.
We import the gsap@3.15 here, all the demos running at this page could edit to trigger animate.
// import the library
gsap.version
学习 Learning
基础 Base
这章基本可以跳过, 基本就是CSS transform的GSAP API写法, 不过确实很简洁.
This chapter is easy to learn since I am familiar with the related CSS attributes. But GSAP is with a simple way to write.
To and From
我已经直接设置了box居中作为初始位置.
I have set the box in center of the row with margin:auto.
const toFunction = () => {
gsap.set("#box1", { x: 0 })
void gsap.to("#box1", { x: 100 })
}
document.querySelector("#box1-to").onclick = toFunction
void toFunction()
const fromFunction = () => {
gsap.set("#box1", { x: 0 })
void gsap.from("#box1", { x: -100 })
}
document.querySelector("#box1-from").onclick = fromFunction
const fromTo = () => {
gsap.set("#box1", { x: 0 })
void gsap.fromTo("#box1", { x: -100 }, { x: 100})
}
document.querySelector("#box1-from-to").onclick = fromTo
Other params
const testOtherParams = () => {
gsap.killTweensOf("#box2")
gsap.set("#box2", { x: 0, scale: 1, rotation: 0, opacity: 1 })
void gsap.to("#box2", {
x: 100, // transform: translateX(100px)
// y: 100, // transform: translateY(100px)
// xPercent: 50, // transform: translateX(50%)
// yPercent: 50, // transform: translateY(50%)
// scale: 2, // transform: scale(2)
// scaleX: 2, // transform: scaleX(2)
// scaleY: 2, // transform: scaleY(2)
// rotation: 90, // transform: rotate(90deg)
// skew: 30, // transform: skew(30deg)
// skewX: 30, // transform: skewX(30deg)
// skewY: "1.23rad", // transform: skewY(1.23rad)
// transformOrigin: "center 40%", // transform-origin: center 40%
// opacity: 0, // adjust the elements opacity
// autoAlpha: 0, // shorthand for opacity & visibility
// duration: 1, // animation-duration: 1s
// repeat: -1, // animation-iteration-count: infinite
// repeat: 2, // animation-iteration-count: 3
// delay: 2, // animation-delay: 2s
// yoyo: true, // animation-direction: alternate
})
}
void testOtherParams();
document.querySelector("#box2-button").onclick = testOtherParams
Modify the SVG
const testSVG = () => {
gsap.set("#rect", {
x: 0,
attr: {
fill: "#28a92b"
}
})
void gsap.to("#rect", {
x: 20,
duration: 2,
attr: {
fill: "#9d95ff",
},
})
}
void testSVG();
document.querySelector("#svg-button").onclick = testSVG
Easing
这一章略了, 官方文档配的坐标系看起来很直观.
We pass the demo for this,
https://gsap.com/resources/getting-started/Easing
Stagger
GSAP的强大在这章初步体现, 交错动画不需要人工调度.
It begins showing the power since this chapter.
const staggers = () => {
gsap.killTweensOf(".stagger-box")
void gsap.to(".stagger-box", {
y: 50,
// stagger: 0.25,
repeat: -1,
stagger: {
amount: 1,
// each: 0.25,
// from: 'center',
// grid: 'auto',
// axis: 'x',
ease: 'power2.inOut',
}
})
}
document.querySelector("#staggers-button").onclick = staggers
void staggers()
Timeline
上一章节的stagger是预制版的timeline实现, GSAP以一条总的globalTimeline为基准管理调度所有动画.
GSAP manages all the animations with one globalTimeline, and the stagger in the previous chapter could be considered as pre-configured implementation of a timeline.
const timeline = () => {
// reset
gsap.set(["#timeline-box1", "#timeline-box2", "#timeline-box3"], { x: 0 })
// create a timeline
let tl = gsap.timeline()
// add the tweens to the timeline - Note we're using tl.to not gsap.to
tl.to("#timeline-box1", { x: 300, duration: 2 });
tl.to("#timeline-box2", { x: 300, duration: 1, delay: 1 });
tl.to("#timeline-box3", { x: 300, duration: 1 });
}
document.querySelector("#timeline-button").onclick = timeline
void timeline()
他还有一个position参数更方便的管理动画, 顺序基于上一个动画的结束时间.
It also support a param we could call it position, the * below.
tl.to("#timeline-box1", { x: 300, duration: 2 }, *);
| 写法 | 含义 |
|---|---|
| 数字(如 1、0.5) | 绝对时间:从 timeline 开头算起的秒数。 |
"+=0.5" | 相对于上一段动画结束,再延迟 0.5 秒后开始(基于「上一段结束」的相对时间)。 |
"-=0.5" | 比上一段动画结束提前 0.5 秒开始(与上一段动画重叠)。 |
"<" | 与上一条子动画的开始时刻对齐(同一时刻开始)。 |
"<0.5" | 在上一条动画开始后 0.5 秒再开始。 |
">" | 与上一条子动画的结束时刻对齐(上一条刚结束时开始)。 |
">0.5" | 在上一条动画结束后 0.5 秒再开始。 |
| Syntax | Meaning |
|---|---|
| Number (e.g. 1, 0.5) | Absolute time in seconds from the start of the timeline. |
"+=0.5" | Start after the previous animation ends, with an additional 0.5s delay (relative to previous end). |
"-=0.5" | Start 0.5s before the previous animation ends (overlapping the previous). |
"<" | Align with the start time of the previous animation (start together). |
"<0.5" | Start 0.5s after the previous animation has started. |
">" | Align with the end time of the previous animation (start when previous finishes). |
">0.5" | Start 0.5s after the previous animation has finished. |
Control and Callback
let ctrlTween = null
const makeProgressTween = () => {
gsap.killTweensOf("#ctrl-progress-fill")
gsap.set("#ctrl-progress-fill", { width: "0%" })
const lab = document.querySelector("#ctrl-progress-label")
if (lab) lab.textContent = "0%"
ctrlTween = gsap.to("#ctrl-progress-fill", {
width: "100%",
duration: 5,
ease: "none",
onUpdate() {
const el = document.querySelector("#ctrl-progress-label")
if (el) el.textContent = Math.round(this.progress() * 100) + "%"
},
onComplete() {
const el = document.querySelector("#ctrl-progress-label")
if (el) el.textContent = "100%"
},
})
}
makeProgressTween()
document.querySelector("#ctrl-btn-pause").onclick = () => { if (ctrlTween) ctrlTween.pause() }
document.querySelector("#ctrl-btn-resume").onclick = () => { if (ctrlTween) ctrlTween.resume() }
document.querySelector("#ctrl-btn-reverse").onclick = () => { if (ctrlTween) ctrlTween.reverse() }
document.querySelector("#ctrl-btn-seek-0").onclick = () => { if (ctrlTween) ctrlTween.seek(0) }
document.querySelector("#ctrl-btn-seek-25").onclick = () => { if (ctrlTween) ctrlTween.seek(1.25) }
document.querySelector("#ctrl-btn-seek-50").onclick = () => { if (ctrlTween) ctrlTween.seek(2.5) }
document.querySelector("#ctrl-btn-progress-half").onclick = () => { if (ctrlTween) ctrlTween.progress(0.5, false) }
document.querySelector("#ctrl-btn-ts-05").onclick = () => ctrlTween && (ctrlTween.timeScale(0.5))
document.querySelector("#ctrl-btn-ts-1").onclick = () => ctrlTween && (ctrlTween.timeScale(1))
document.querySelector("#ctrl-btn-ts-2").onclick = () => ctrlTween && (ctrlTween.timeScale(2))
document.querySelector("#ctrl-btn-restart").onclick = makeProgressTween
0%