動畫相關的 API 都是在 @angular/animations
裡面引入的。
import { 你想要的API } from `@angular/animations`;
複製程式碼
trigger : 由它觸發動畫效果,稱動畫觸發器。
function trigger(
name: string,
definitions: AnimationMetadata[]
):AnimationTriggerMetadata;
複製程式碼
-
name
動畫觸發器名字, 如
growWidth
-
definitions
要執行的動畫, 如
[ transition("void => *", [style({opacity: 0}), animate(600, style({ opacity: 1}))] )],
state :定義目標處於某一狀態時的樣式
function state(
name: string,
styles: AnimationStyleMetadata,
options?: {params: {[name: string]: any}}
):AnimationStateMetadata;
複製程式碼
-
name
當前狀態的名字,可以有多個名字,用逗號隔開,如:
`active,clicked`
。
這個name還可以用void
和*
表示:void
代表動畫執行前元件的狀態;*
代表動畫執行後元件的狀態,即元件的預設狀態。 -
styles
處於這個狀態時的樣式,如
style({width: 0})
-
options : 可選項。
transition:狀態之間轉換處理函式
function transition(
stateChangeExpr: string,
steps: AnimationMetadata | AnimationMetadata[],
options: AnimationOptions | null = null
):AnimationTransitionMetadata;
複製程式碼
-
stateChangeExpr
A=>B,狀態轉換表示式,即從哪個狀態切換到哪個狀態。支援以下寫法:
- 狀態改變時啟動動畫
transition("void => *", animate(500)) 複製程式碼
- 可以在兩個狀態變化上執行相同動畫
transition("void <=> *", animate(500)), 複製程式碼
- 也可以定義幾對狀態切換執行同一動畫
transition("on => off, off => void", animate(500)), 複製程式碼
-
steps
animate(),動畫執行步驟,即幾秒執行完,執行曲線是怎樣的。
如animate(`100ms ease-in`)
或是一個陣列[animate(`100ms ease-in`),animate(600)]
-
options
可以傳入動畫的延遲值和動畫輸入引數,以更改計時資料和樣式。詳見
AnimationOptions
函式。
用法
其實狀態 transition("void => *", animate(500))
表示的是進入,在這裡可以用 :enter
表示:
transition(":enter", animate(500))
複製程式碼
同理 transition(" *=> void", animate(500))
離開可以這樣寫:
transition(":leave", animate(500))
複製程式碼
animate : 動畫
function animate(
timings: string | number,
styles: AnimationStyleMetadata | AnimationKeyframesSequenceMetadata |null = null
): AnimationAnimateMetadata;
複製程式碼
-
timings :
duration delay easing
它是一個字串,有三個引數:
- duration : 動畫持續時間
- delay : 動畫延遲幾秒後開始
- easing : 動畫的緩和程度
如果只有一個數字,那麼會被認為是 duration 的值。如:
animate("200 ease-in", ...) // 被編譯成 duration=200, easing=ease-out animate("200 1000 ease-in", ...) // 被編譯成 duration=200, delay=1000, easing=ease-out 複製程式碼
-
styles
它可以是 style(樣式) 或 keyframes(關鍵幀),具體用法看下面詳細介紹。
animate(timings, style({ background: "red" })) animate(timings, keyframes([ style({ background: "blue", offset: 0.2})), // 20% style({ background: "red", offset: 1})) // 100% ]) 複製程式碼
style : 樣式設定
function style(
tokens: `*` |
{[key: string]: string | number} |
Array<`*`|{[key: string]: string | number}>
): AnimationStyleMetadata;
複製程式碼
style宣告一個包含CSS屬性/樣式的鍵值對。
style({ width: 100, height: 0 })
複製程式碼
Auto-styles(自適應樣式): style值可以用 `*` 來表示,自動達到其原本的樣式,舉個例子你就明白作用了:
如果一個div它實際寬度是100px,高度為100px,讓它高度從0 到100px變化
<div class=`demo`></div>
...
.demo{
width: 100px;
height: 100px;
}
複製程式碼
這時候用 `*`來寫
animations: [trigger(
`autoHeight`,
[
state(`void`, style({height: `0px`})),
state(`*`, style({height: `*`})),
transition(`void => *`, animate(500))
])],
複製程式碼
它就會在 500ms內 高度從 0 搭配100px。咦,似乎沒感覺到什麼作用…
在高度為動態獲取的值時候就看到其強大了:data為動態獲取的{ height: xxx }
<div class=`demo` [ngStyle]="{`height`:data.height}">
</div>
...
.demo{
width: 100px;
}
複製程式碼
animations: [trigger(
`autoHeight`,
[
state(`void`, style({height: `0px`})),
state(`*`, style({height: `*`})),
transition(`void => *`, animate(500))
])],
複製程式碼
這樣在 500ms 高度自動到達設定的值。
keyframes:關鍵幀
function keyframes(
steps: AnimationStyleMetadata[]
): AnimationKeyframesSequenceMetadata;
複製程式碼
它的引數是一個style()
的陣列,表示步驟。
animate("5s", keyframes([
style({ backgroundColor: "red", offset: 0 }), // 0%
style({ backgroundColor: "blue", offset: 0.2 }), // 20%
style({ backgroundColor: "orange", offset: 0.3 }), // 30%
style({ backgroundColor: "black", offset: 1 }) // 100%
]))
複製程式碼
這裡的 offset 和css3 keyframes裡面的百分比一樣,是時間的偏移量。
offset: 0.2表示動畫在 20%的時候的樣式。
此外,如果沒有設定偏移量,那麼偏移量將自動計算
animate("5s", keyframes([
style({ backgroundColor: "red" }) // offset = 0
style({ backgroundColor: "blue" }) // offset = 0.33
style({ backgroundColor: "orange" }) // offset = 0.66
style({ backgroundColor: "black" }) // offset = 1
]))
複製程式碼
query: 選取元素,並新增動畫
function query(
selector: string,
animation: AnimationMetadata | AnimationMetadata[],
options: AnimationQueryOptions | null = null
): AnimationQueryMetadata;
複製程式碼
- selector : 要選取的元素,選取方式和原生的一樣。
- animation : 要進行的動畫序列,一個或多個。
作用:
在處於動畫序列的元素內部查詢一個或多個元素,這些元素也會被加入當前動畫序列中,不過一般會重新寫一個陣列來重新定義選取元素的動畫序列。
用法:
1) 選取元素並可以限制數量
query()函式原始碼中使用了element.querySelectorAll
因此他可以選取多個元素,所以我們在選取元素的時候可以加上一個 limit
來限制選取的數量。
// 在class為 demo的div裡找一個div,找到的是 demo1,如果 limit為2 的話找到的是 [demo1, demo2]。
template: `
<div [@queryDemo] class=`demo`>
<div class=`demo1`></div>
<div class=`demo2`></div>
</div>
`,
animations: [
trigger(`queryDemo`, [
transition(`void => *`, [
query( `div`, animate(...), {limit: 1} )
])
]
]
複製程式碼
2) 報錯功能
預設情況下如果選取的元素找不到則 query()函式會報錯,設定optional
選項為 true 則或忽略錯誤。
query(`.demo-not-be-there`, [
animate(...),
animate(...)
], { optional: true })
複製程式碼
選擇器的特殊值
query()函式裡面用偽選擇器可以選出特定的元素:
query(":enter")/query(":leave")
: 選取新插入 / 移除的元素query(":animating")
: 選取所有正在進行動畫的元素query("@triggerName")
: 選取有特定觸發器的元素query("@*")
: 選取所有具有觸發器的元素query(":self")
: 把當前元素增加到動畫序列中
多個偽選擇器可以合在一起組成選擇器查詢字串:
query(`:self, .record:enter, .record:leave, @subTrigger`, [...])
複製程式碼
例子
@Component({
selector: `inner`,
template: `
<div [@queryAnimation]="exp">
<h1>Title</h1>
<div class="content">
Blah blah blah
</div>
</div>
`,
animations: [
trigger(`queryAnimation`, [
transition(`* => goAnimate`, [
// 隱藏裡面的元素
query(`h1`, style({ opacity: 0 })),
query(`.content`, style({ opacity: 0 })),
// 一個一個地執行裡面元素的動畫
query(`h1`, animate(1000, style({ opacity: 1 })),
query(`.content`, animate(1000, style({ opacity: 1 })),
])
])
]
})
class Cmp {
exp = ``;
goAnimate() {
this.exp = `goAnimate`;
}
}
複製程式碼
sequence : 序列
function sequence(
steps: AnimationMetadata[],
options: AnimationOptions | null = null
): AnimationSequenceMetadata;
複製程式碼
-
steps : 動畫序列的步驟
它可以由樣式或動畫函式呼叫組成。對style()的呼叫將立即應用提供的樣式資料,而對animate()的呼叫將在它延遲時間後應用它的樣式資料。
-
options: 參見 AnimationOptions
// 這是一個動畫序列
sequence([
style({ opacity: 0 })),
animate("1s", { opacity: 1 }))
])
複製程式碼
那到底什麼是序列呢?
它是一個動畫列表[A,B,C],裡面的動畫挨個執行:執行完A再執行B,B執行完再執行C。
它可以應用在 group
和transition
裡面,它只會在每個內部動畫步驟完成後再繼續執行下一條指令。
將一個陣列作為動畫資料傳遞到transition時,預設使用序列。如下面的[animate(500, style({...})), animate(500)]
就是序列。
animations: [trigger(
`demo`,
[
state(`void`, style({...})),
state(`*`, style({...})),
transition(
`void => *`, [animate(500, style({...})), animate(500)])
])],
複製程式碼
它和組(group)的異同:
都是動畫列表,序列是一個一個執行,組是並行執行。
group : 組
function group(
steps: AnimationMetadata[],
options: AnimationOptions | null = null
): AnimationGroupMetadata;
複製程式碼
- steps : 動畫步驟資料
它可以由樣式或動畫函式呼叫組成。在一個組中,每個樣式或動畫函式的呼叫都會立即同時執行,當然你可以使用關鍵幀或者動畫的延遲函式來延遲執行動畫。 - options: 參見
AnimationOptions
group([
animate("1s", { background: "black" }))
animate("2s", { color: "white" }))
])
複製程式碼
什麼是組呢?
組是一個並行執行的動畫步驟列表。當存在很多樣式在不同時間段開始或結束動畫,我們需要對它統一進行管理的時候作用非常明顯。利用組我們可以輕易控制它們同時開始動畫或者同時結束動畫。
group函式既可以在序列(sequence
)中使用,也可以在轉換(transition
)中使用,它只會在所有內部動畫步驟完成後繼續執行下一條指令。
AnimationOptions :動畫的可選項
import { AnimationOptions } from `@angular/animations`;
複製程式碼
interface AnimationOptions {
delay?: number|string
params?: {[name: string]: any}
}
複製程式碼
- delay: number|string
動畫的延遲值。 - params
在啟動動畫時傳入引數,以更改樣式。
以下動畫函式可配置 AnimationOptions:
- transition()
- sequence()
- group()
- query()
- animation()
- useAnimation()
- animateChild()
- 使用AnimationBuilder服務構建的動畫
子介面
- AnimateChildOptions
- AnimationQueryOptions
例項: 比如現在想做一個動畫效果 : 點選按鈕 div 寬從 0 到100px。
- 新增動畫觸發器
// ts
import { trigger } from `@angular/core`;
@Component({
templateUrl: `my-demo.html`,
animations: [
trigger( `growWidth`, [ // 這裡是定義的一些動畫效果] )
]
})
// html
<div [@growWidth]>...</div>
複製程式碼
- 再進行狀態(寬度)的改變
import { trigger, state, style } from `@angular/core`;
@Component({
templateUrl: `my-demo.html`,
animations: [
trigger( `growWidth`, [
state( `smWidth, void`, style({width: `0px`}) ),
state( `lgWidth`, style({width: `100px`}) )
] )
]
})
複製程式碼
上面定義了兩個狀態,一個是寬度最小時候為0,一個寬度最大時候為 100px;
那麼有growWidth 動畫觸發器的 div 會完成這個寬度 0 到100px的動畫。
- 上面雖然完成了兩個不同狀態之間的改變,但是沒有過渡效果,用transition實現過渡。
import { trigger, state, transition, animate } from `@angular/core`;
@Component({
templateUrl: `my-demo.html`,
animations: [
trigger( `growWidth`, [
state( `smWidth, void`, style({width: `0px`}) ),
state( `lgWidth`, style({width: `100px`}) ),
transition(`smWidth => lgWidth`, animate(600)),
transition(`lgWidth => smWidth`, animate(600)),
] )
]
})
複製程式碼
上面規定了從 smWidth 狀態到 lgWidth狀態需要0.6s的時間,所以可以看到div的寬度是慢慢變大的。
| 更多API用法更新於 github