Variants 可以讓元件以字串的方式帶入動畫,同時可以把相同的動畫抽出來,可以說是動畫的影分身之術,此外還有傳播的功能,可以使子元件相同 key 的動畫一起動起來。
在之前都是在個別動畫 props 帶入物件,並且 initial
與 animate
都共用同一個 transition
設定 :
<motion.div
initial={{ ... }}
animate={{ ... }}
transition={{ ... }}
/>
variants
可以看做加強版動畫包,更進一步提供 variants
的 props 屬性可以把所有設定提出來,並且可以個別調整動畫 props 的 transition
設定 :
// 建立 variants
const boxVariants={
hidden :{
x : -100
// 個別設定
transition:{
...
}
},
show:{
x : 0
// 個別設定
transition:{
...
}
}
}
// 在 motion component 使用
<motion.div
initial= "hidden" // 用 字串 代替物件
animate="show" // 用 字串 代替物件
variants={boxVariants} // 記得加上 variants
/>
官方雖然寫 hidden
跟 show
,但 只是建議取名,實際上要取什麼名字都可以,符合語意就好。
到本篇為止只有提到控制單個元素動畫, variants
可以把相同的動畫編排提出來,讓動畫能夠應用在不同元件上,不過巢狀元素動畫是很常使用的 variants
的概念的。
這時候可能想,阿提出去之後如果要搭配 React 資料流來改變怎麼辦 ? 是這樣嗎 ?
<motion.div
initial= "hidden"
animate="show"
variants={boxVariants(myState)} // 變成 funciton
/>
每次都傳入新的 function 並不是好的操作 :( ,如果知道 React 的渲染機制會進行淺比較,這樣導致有關無關都會重新觸發動畫。
好在 motion 元件可以加入 custom
props 屬性,在 variants 物件中使用函式,最多接收一個參數 :
const boxVariants={
// 接收一個參數 custom
hidden : (custom) => {
// 一樣回傳物件
return ({
opacity : custom
transition:{
...
}
})
}
}
<motion.div
initial= "hidden"
animate="show"
variants={boxVariants}
custom={1} // 加入 custom props
/>
在 JavaScript 的事件機制裡,有先捕獲後冒泡的概念,如果子層或父層同時帶有事件監聽,點擊事件也會被傳播而觸發,在 motion 元件裡也有這個概念。
如果 motion 元件的子元件的 variants
的 initial
與 animate
也都叫同一個名字,只要傳入 variants 不用特別設定那兩個動畫 props 的字串,當父元件觸發時 motion 也會一併觸發相同的子元件的動畫。除非子元件自己訂動畫蓋過去。
簡單來說,我們不需要再為子元件一個個添加 initial
與 animation
字串
const parent = {
show : {...},
hidden : {...}
};
const child ={
show : {...},
hidden : {...}
}
<motion.div
variants={parent}
initial="hidden"
animate="show"
>
<motion.span
variants={child} // 這裡只要填 variants 就好
>
Child
<motion.span>
</motion.div>
當父元件觸發動畫,子元件也會跟著動,如果 key 的名字沒對不到就不會動。
yoyo
就打斷傳鏈了。transition 除了基本的屬性外,還提供可以控制子元件與本身元件出現的時間點 :
when
: 本身元素的動畫觸發時間點,有 false
、 "beforeChildren"
、"afterChildren"
,子動畫前/後,或是通通一起出現的 false。staggerChildren
: 底下子元件按照節點順序動畫的時間,比如 1 號結束才會換 2 號,等於 Item(n) = Item(n-1) 的時間 + StaggerTime
,就是累加的延遲時間。還有延遲跟反轉順序的屬性,後面會再提到,這兩個使用上就蠻綽綽有餘的。
// 父元件動畫,設定子元件的照順序的延遲時間
const boxVariants = {
show: {
background: "#fa0", // 顏色會再子元素都跑完後才會觸發
transition: {
when: "afterChildren", // 再子元素之後才啟動動畫
staggerChildren: 0.2,
},
},
};
// 把個別文字設定腳本
const wordVariants = {
show: {
opacity: 1,
y: 0,
},
hidden: {
opacity: 0,
y: 20,
},
};
let name = "RosaHong";
export default function NameFloating() {
return (
<motion.div
className="wordContainer"
initial="hidden"
animate="show"
variants={boxVariants}
>
{name.split("").map((word) => (
<motion.span
key={word}
className="nameWord"
variants={wordVariants} // 只要添加 variants
>
{word}
</motion.span>
))}
</motion.div>
);
}
variants
: 加強版 initial
與 animate
可以個別控制 transition
屬性。custom
props : 傳到 variants 物件作為函式接收一個參數。variants
所使用的 animation 與 initial 字串名會延續到子元件的 variants 。如果子元件的 variants 沒有對應 key-name 則不會動。transition
props 控制子元件的動畫編排方式以及本身要在子元件動畫結束/開始啟動。明天會介紹很奇妙的 layout
props。
鄰近 921 有點敏感,雖然我沒有經歷過,但這兩天被地震嚇得不輕,心神不寧難以坐下來好好寫文 @@,希望大家都平安。