# JS動畫製作
JS的第一個應用,就先從動畫開始好了
## GSAP動畫
目標是做出能讓網頁元素隨著向下滑動淡入,且不同元素有不同的進場方向的動畫,而在眾多的libraries中我選擇用GSAP,沒為什麼,只是找到的資源比較多XD
### GSAP起手式
要先從HTML引入library,一個是主library,一個是額外的ScrollTrigger
```htmlembedded=
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.8.0/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.8.0/ScrollTrigger.min.js"></script>
```
而JS裡面要有ScrollTrigger的Plugin
```javascript=
gsap.registerPlugin(ScrollTrigger);
```
這樣環境就架設好了,開始打酷酷的動畫吧~
### 主動畫製作
講講GSAP 3的基礎語法
```javascript=
gsap.from(".keyboard", { //選取物件
scrollTrigger: {
trigger: ".keyboard",
start: "top 30%", //當物件抵達視窗30%高度時開始
end: "bottom 100%", //當物件抵達視窗底部時結束
scrub: true, //動畫隨著捲動推移
toggleActions: "restart pause reverse pause" //在視窗外不移動,往上捲時動畫倒轉
}, //scrollTrigger特效
opacity: 0, //從透明淡入
duration: 1.5, //維持1.5s
x: 25*1.73, //x方向位移
y: 25 //y方向位移
});
```
如此一來鍵盤就有了進場動畫

但因為再幫螢幕、視窗一、視窗二等其他三個元素寫三次相似的code有點不美觀,所以我把他們統整到陣列跟object裡,用字串格式化美化
```javascript=
const hobbyElements = [
{name: "keyboard", x: 25*1.73, y: 25},
{name: "window1", x: -25*1.73, y: 25},
{name: "window2", x: 25*1.73, y: -25},
{name: "screen", x: -25*1.73, y: -25}
];
for(hobbyElement of hobbyElements) {
gsap.from(`.${hobbyElement.name}`, {
scrollTrigger: {
trigger: `.${hobbyElement.name}`,
start: "top 30%",
end: "bottom 100%",
scrub: true,
toggleActions: "restart pause reverse pause"
},
opacity: 0,
duration: 1.5,
x: hobbyElement.x,
y: hobbyElement.y
});
}
```
然後就能得到更酷的動畫

### 配合responsive layout
但是...在我把網頁縮小後就出事了,網頁排版能跟著視窗大小調整但動畫的起始、結束點不行,因此就出現動畫卡住、動畫出不來或是閃現出來諸如此類的bug

然後在不停找資料後,只有找到xPercent, yPercent等好像沒有在GSAP 3用的東西,最後甚至跑去stack overflow問大佬XD,但有點溝通障礙,果然我問問題的方法還是太拙劣了,一開始還忘了放codepen
最後回到youtube意外找到start, end用method寫的方法,終於解決這問題
```javascript=
const computer = document.querySelector(".hobby-image");
for(hobbyElement of hobbyElements) {
gsap.from(`.${hobbyElement.name}`, {
scrollTrigger: {
trigger: `.${hobbyElement.name}`,
start: () => `top ${window.screen.availHeight * 0.4 + computer.offsetTop * 0.8}`,
//原本的視窗40% + 80%電腦離容器頂端的距離來因應文字跑到上方的情況
end: () => `+=${computer.getBoundingClientRect().height * 0.3}`,
// 動畫結束改設為起始點以下30%電腦高度
scrub: true,
toggleActions: "restart pause reverse pause"
},
opacity: 0,
duration: 1.5,
x: hobbyElement.x,
y: hobbyElement.y
});
}
```
這樣酷酷的動畫就能在各種視窗大小觀賞了

個人照的動畫就如法炮製就好,喔耶~
```javascript=
const imageScrollFunction = () => {
const image = document.querySelector(".my-image");
gsap.from(".personal-photo", {
scrollTrigger: {
trigger: ".personal-photo",
start: () => `top ${window.screen.availHeight * 0.3 + image.offsetTop * 0.8}`,
toggleActions: "restart pause reverse reverse",
},
ease: "expo.out", //劇烈漸慢
clipPath: "polygon(0 100%, 100% 100%, 100% 100%, 0 100%)", //裁切
y: 50,
duration: 3
});
}
```
個人照的動畫不用像電腦一樣那麼複雜,改成用裁切展開的特效

順帶一提,照片裡那隻是我們校狗,他叫大黑
## 小小的結語
寫動畫真的挺好玩的,雖然中間debug的時候真的讓我很頭痛,下一篇就是navbar~
---
<ul style ="display: flex; flex-direction: row; width: 100%; justify-content: space-between;margin: 0; padding: 0;">
<li style="list-style: none;"><a href = "https://hackmd.io/@WeberChang/BkCAZwj_Y" >上一篇</a></li>
<li style="list-style: none;"><a href = "https://hackmd.io/@WeberChang/rJBpwRsut">主頁</a></li>
<li style="list-style: none;"><a href = "https://hackmd.io/@WeberChang/Bysh-oH5K">下一篇</a></li>
</ul>