動(dòng)畫用于提供運(yùn)動(dòng)的幻覺:HTML 元素隨著時(shí)間改變樣式。精心設(shè)計(jì)的動(dòng)畫可以讓你的應(yīng)用更有趣,更易用,但它們不僅僅是裝飾性的。動(dòng)畫可以通過幾種方式改善你的應(yīng)用和用戶體驗(yàn):
典型的動(dòng)畫會(huì)涉及多種隨時(shí)間變化的轉(zhuǎn)換。HTML 元素可以移動(dòng)、變換顏色、增加或縮小、隱藏或從頁面中滑出。這些變化可以同時(shí)發(fā)生或順序發(fā)生。你可以控制每次轉(zhuǎn)換的持續(xù)時(shí)間。
Angular 的動(dòng)畫系統(tǒng)是基于 CSS 功能構(gòu)建的,這意味著你可以 "動(dòng)" 瀏覽器認(rèn)為可動(dòng)的任何屬性。包括位置、大小、變形、顏色、邊框等。W3C 在它的 CSS Transitions(轉(zhuǎn)場) 頁中維護(hù)了一個(gè)可動(dòng)屬性的列表。
本指南覆蓋了基本的 Angular 動(dòng)畫特性,讓你能開始為你的項(xiàng)目添加 Angular 動(dòng)畫。
本指南中描述的特性,以及相關(guān)的 Angular 動(dòng)畫章節(jié)中描述的更多高級(jí)特性,都在一個(gè)范例 現(xiàn)場演練 / 下載范例 中進(jìn)行了演示。
Angular 主要的動(dòng)畫模塊是 ?@angular/animations
? 和 ?@angular/platform-browser
?。當(dāng)你使用 CLI 創(chuàng)建新項(xiàng)目時(shí),這些依賴會(huì)自動(dòng)添加到你的項(xiàng)目中。
為了把 Angular 動(dòng)畫添加到你的項(xiàng)目中,把這些與動(dòng)畫相關(guān)的模塊和標(biāo)準(zhǔn)的 Angular 功能一起導(dǎo)入進(jìn)來。
導(dǎo)入 ?BrowserAnimationsModule
?,它能把動(dòng)畫能力引入 Angular 應(yīng)用的根模塊中。
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
imports: [
BrowserModule,
BrowserAnimationsModule
],
declarations: [ ],
bootstrap: [ ]
})
export class AppModule { }
注意:
當(dāng)你使用 CLI 創(chuàng)建應(yīng)用時(shí),應(yīng)用的根模塊 ?app.module.ts
? 位于 ?src/app
? 目錄下。
如果你準(zhǔn)備在組件文件中使用特定的動(dòng)畫函數(shù),請(qǐng)從 ?@angular/animations
? 中導(dǎo)入這些函數(shù)。
import { Component, HostBinding } from '@angular/core';
import {
trigger,
state,
style,
animate,
transition,
// ...
} from '@angular/animations';
在組件的 ?@Component()
? 裝飾器中,添加一個(gè)名叫 ?animations:
? 的元數(shù)據(jù)屬性。你可以把用來定義動(dòng)畫的觸發(fā)器放進(jìn) ?animations
?元數(shù)據(jù)屬性中。
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css'],
animations: [
// animation triggers go here
]
})
我們來做一個(gè)簡單的轉(zhuǎn)場動(dòng)作,它把單個(gè) HTML 元素從一個(gè)狀態(tài)變成另一個(gè)狀態(tài)。比如,你可以指定按鈕根據(jù)用戶的最后一個(gè)動(dòng)作顯示成Open或Closed狀態(tài)。當(dāng)按鈕處于 ?open
?狀態(tài)時(shí),它是可見的,并且是黃色的。當(dāng)它處于 ?closed
?狀態(tài)時(shí),它是透明的,并且是藍(lán)色的。
在 HTML 中,這些屬性都使用普通的 CSS 樣式,比如顏色(color)和透明度(opacity)。在 Angular 中,使用 ?style()
? 函數(shù)來指定一組用作動(dòng)畫的 CSS 樣式??梢詾閯?dòng)畫狀態(tài)指定一組樣式,并為該狀態(tài)指定一個(gè)名字,比如 ?open
?或 ?closed
?。
我們創(chuàng)建一個(gè)具有簡單轉(zhuǎn)場動(dòng)畫的 ?open-close
? 組件。
在終端窗口運(yùn)行下列命令以生成該組件:ng g component open-close
這會(huì)在 ?
src/app/open-close.component.ts
? 下創(chuàng)建此組件。
使用 Angular 的 ?state()
? 函數(shù)來定義不同的狀態(tài),供每次轉(zhuǎn)場結(jié)束時(shí)調(diào)用。該函數(shù)接受兩個(gè)參數(shù):一個(gè)唯一的名字,比如 ?open
?或 ?closed
?和一個(gè) ?style()
? 函數(shù)。
使用 ?style()
? 函數(shù)來定義一組與指定的狀態(tài)名相關(guān)的樣式。名稱里帶中線的樣式屬性必須是小駝峰 格式的,如 ?backgroundColor
?,或者把它們包裹到引號(hào)里,如 ?'background-color'
?。
我們來看看 Angular 的 ?state()
? 函數(shù)如何與 ?style()
? 函數(shù)聯(lián)用,來設(shè)置 CSS 樣式的屬性。 在下面的代碼片段中,該狀態(tài)的多個(gè)樣式屬性都是同時(shí)設(shè)置的。在 ?open
?狀態(tài)中,該按鈕的高度是 200 像素,透明度是 1,背景色是黃色。
// ...
state('open', style({
height: '200px',
opacity: 1,
backgroundColor: 'yellow'
})),
在下面這個(gè) ?closed
?狀態(tài)中,按鈕的高度是 100 像素,透明度是 0.5,背景色是綠色。
state('closed', style({
height: '100px',
opacity: 0.8,
backgroundColor: 'blue'
})),
在 Angular 中,你可以設(shè)置多個(gè)樣式而不必用動(dòng)畫。不過,如果沒有進(jìn)一步細(xì)化,按鈕的轉(zhuǎn)換會(huì)立即完成 —— 沒有漸隱、沒有收縮,也沒有其它的可視化效果來指出正在發(fā)生變化。
要讓這些變化不那么突兀,就要定義一個(gè)動(dòng)畫轉(zhuǎn)場來要求這些狀態(tài)之間的變化在一段時(shí)間內(nèi)發(fā)生。?transition()
? 接受兩個(gè)參數(shù):第一個(gè)參數(shù)接受一個(gè)表達(dá)式,它定義兩個(gè)轉(zhuǎn)場狀態(tài)之間的方向;第二個(gè)參數(shù)接受一個(gè)或一系列 ?animate()
? 函數(shù)。
使用 ?animate()
? 函數(shù)來定義長度、延遲和緩動(dòng)效果,并指定一個(gè)樣式函數(shù),以定義轉(zhuǎn)場過程中的樣式??梢杂?nbsp;?animate()
? 函數(shù)來為多步動(dòng)畫定義 ?keyframes()
? 函數(shù)。這些定義放在 ?animate()
? 函數(shù)的第二個(gè)參數(shù)中。
?animate()
? 函數(shù)(作為轉(zhuǎn)場函數(shù)的第二個(gè)參數(shù))可以接受 ?timings
?和 ?styles
?參數(shù)。
?timings
?參數(shù)可以接受一個(gè)數(shù)字或由三部分組成的字符串。
animate (duration)
或者
animate ('duration delay easing')
第一部分 ?duration
?(持續(xù)時(shí)間)是必須的。這個(gè)持續(xù)時(shí)間可以表示成一個(gè)不帶引號(hào)的純數(shù)字(表示毫秒),或一個(gè)帶引號(hào)的有單位的時(shí)間(表示秒數(shù))。比如,0.1 秒的持續(xù)時(shí)間有如下表示方式:
100
?'100ms'
?'0.1s'
?第二個(gè)參數(shù) ?delay
?的語法和 ?duration
?一樣。比如:
'0.2s 100ms'
?第三個(gè)參數(shù) ?easing
?控制動(dòng)畫在運(yùn)行期間如何進(jìn)行加速和減速。比如 ?ease-in
? 表示動(dòng)畫開始時(shí)很慢,然后逐漸加速。
'0.2s 100ms ease-out'
?'0.2s ease-in-out'
?'0.2s ease-in'
?注意:
有關(guān)緩動(dòng)曲線的一般信息,參閱 Material Design 網(wǎng)站上關(guān)于自然緩動(dòng)曲線的主題。
下面的例子提供了一個(gè)從 ?open
?到 ?closed
?的持續(xù)一秒的狀態(tài)轉(zhuǎn)場。
transition('open => closed', [
animate('1s')
]),
在上面的代碼片段中,?=>
? 操作符表示單向轉(zhuǎn)場,而 ?<=>
? 表示雙向轉(zhuǎn)場。在轉(zhuǎn)場過程中,?animate()
? 指定了轉(zhuǎn)場需要花費(fèi)的時(shí)間。在這里,從 ?open
?到 ?closed
?狀態(tài)的轉(zhuǎn)換要花費(fèi) 1 秒中,表示成 ?1s
?。
下面的例子添加了一個(gè)從 ?closed
?到 ?open
?的狀態(tài)轉(zhuǎn)場,轉(zhuǎn)場動(dòng)畫持續(xù) 0.5 秒。
transition('closed => open', [
animate('0.5s')
]),
注意:
在 ?state
?和 ?transition
?函數(shù)中使用樣式時(shí)有一些需要注意的地方。
- 請(qǐng)用 ?
state()
? 來定義那些每個(gè)轉(zhuǎn)場結(jié)束時(shí)的樣式,這些樣式在動(dòng)畫完成后仍會(huì)保留- 使用 ?
transition()
? 來定義那些中間樣式,以便在動(dòng)畫過程中產(chǎn)生運(yùn)動(dòng)的錯(cuò)覺- 當(dāng)禁用了動(dòng)畫時(shí),也會(huì)忽略 ?
transition()
? 中的樣式,但 ?state()
? 中的樣式不會(huì)。- 在同一個(gè) ?
transition()
? 參數(shù)中包含多個(gè)狀態(tài)對(duì):transition( 'on => off, off => void' )
動(dòng)畫需要觸發(fā)器,以便知道該在何時(shí)開始。?trigger()
? 函數(shù)會(huì)把一些狀態(tài)和轉(zhuǎn)場組合在一起,并為這個(gè)動(dòng)畫命名,這樣你就可以在 HTML 模板中把它附加到想要觸發(fā)動(dòng)畫的元素上了。
?trigger()
? 函數(shù)描述了監(jiān)聽變化時(shí)要使用的觸發(fā)器名稱。當(dāng)這個(gè)觸發(fā)器名稱所綁定的值發(fā)生了變化時(shí),觸發(fā)器就會(huì)啟動(dòng)它所定義的操作。這些操作可能是轉(zhuǎn)場,也可能是其它功能,我們稍后就會(huì)看到。
在這個(gè)例子中,我們將把該觸發(fā)器命名為 ?openClose
?,并把它附加到 ?button
?元素上。該觸發(fā)器描述了 ?open
?和 ?closed
?兩個(gè)狀態(tài),以及兩個(gè)轉(zhuǎn)場效果的時(shí)序。
注意:
在每個(gè) ?trigger()
? 函數(shù)調(diào)用中,元素在任意時(shí)刻只能處于其中的一個(gè)狀態(tài)。但是,元素可以在同一時(shí)刻激活多個(gè)觸發(fā)器。
這些控制 HTML 元素如何運(yùn)動(dòng)的動(dòng)畫是在組件的元數(shù)據(jù)中定義的。請(qǐng)?jiān)?nbsp;?@Component()
? 裝飾器的 ?animations:
? 屬性下用代碼定義你要用的動(dòng)畫。
@Component({
selector: 'app-open-close',
animations: [
trigger('openClose', [
// ...
state('open', style({
height: '200px',
opacity: 1,
backgroundColor: 'yellow'
})),
state('closed', style({
height: '100px',
opacity: 0.8,
backgroundColor: 'blue'
})),
transition('open => closed', [
animate('1s')
]),
transition('closed => open', [
animate('0.5s')
]),
]),
],
templateUrl: 'open-close.component.html',
styleUrls: ['open-close.component.css']
})
export class OpenCloseComponent {
isOpen = true;
toggle() {
this.isOpen = !this.isOpen;
}
}
為組件定義好這些動(dòng)畫觸發(fā)器之后,你可以給觸發(fā)器名稱加上 ?@
? 前綴并包在方括號(hào)里,來把它附加到組件模板中的元素上。然后,你可以使用 Angular 的標(biāo)準(zhǔn)屬性綁定語法(如下所示),來把這個(gè)觸發(fā)器綁定到模板表達(dá)式上。這里的 ?triggerName
?就是觸發(fā)器的名稱,而 ?expression
?的求值結(jié)果是前面定義過的動(dòng)畫狀態(tài)之一。
<div [@triggerName]="expression">…</div>;
當(dāng)該表達(dá)式的值變成了新的狀態(tài)時(shí),動(dòng)畫就會(huì)執(zhí)行或者叫觸發(fā)。
下列代碼片段把該觸發(fā)器綁定到了 ?isOpen
?屬性的值上。
<nav>
<button type="button" (click)="toggle()">Toggle Open/Close</button>
</nav>
<div [@openClose]="isOpen ? 'open' : 'closed'" class="open-close-container">
<p>The box is now {{ isOpen ? 'Open' : 'Closed' }}!</p>
</div>
在這個(gè)例子中,當(dāng) ?isOpen
?表達(dá)式求值為一個(gè)已定義狀態(tài) ?open
?或 ?closed
?時(shí),就會(huì)通知 ?openClose
?觸發(fā)器說狀態(tài)變化了。然后,就由 ?openClose
?中的代碼來處理狀態(tài)變更,并啟動(dòng)狀態(tài)變更動(dòng)畫。
對(duì)于那些進(jìn)入或離開頁面的元素(插入到 DOM 中或從中移除),你可以讓動(dòng)畫變成有條件的。比如,在 HTML 模板中可以和 ?*ngIf
? 一起使用動(dòng)畫觸發(fā)器。
注意:
在組件文件中,要把用來定義動(dòng)畫的觸發(fā)器設(shè)置為 ?@Component()
? 裝飾器的 ?animations:
? 屬性的值。
在 HTML 模板文件中,使用這個(gè)觸發(fā)器的名稱來把所定義的這些動(dòng)畫附加到想要添加動(dòng)畫的 HTML 元素上。
下面是轉(zhuǎn)場動(dòng)畫范例中討論過的代碼文件。
@Component({
selector: 'app-open-close',
animations: [
trigger('openClose', [
// ...
state('open', style({
height: '200px',
opacity: 1,
backgroundColor: 'yellow'
})),
state('closed', style({
height: '100px',
opacity: 0.8,
backgroundColor: 'blue'
})),
transition('open => closed', [
animate('1s')
]),
transition('closed => open', [
animate('0.5s')
]),
]),
],
templateUrl: 'open-close.component.html',
styleUrls: ['open-close.component.css']
})
export class OpenCloseComponent {
isOpen = true;
toggle() {
this.isOpen = !this.isOpen;
}
}
<nav>
<button type="button" (click)="toggle()">Toggle Open/Close</button>
</nav>
<div [@openClose]="isOpen ? 'open' : 'closed'" class="open-close-container">
<p>The box is now {{ isOpen ? 'Open' : 'Closed' }}!</p>
</div>
:host {
display: block;
margin-top: 1rem;
}
.open-close-container {
border: 1px solid #dddddd;
margin-top: 1em;
padding: 20px 20px 0px 20px;
color: #000000;
font-weight: bold;
font-size: 20px;
}
?@angular/animations
? 模塊提供的這些功能性 API 提供了一種領(lǐng)域特定語言(DSL),用于在 Angular 應(yīng)用中創(chuàng)建和控制動(dòng)畫效果。
函數(shù)名 |
用途 |
---|---|
trigger()
|
開始動(dòng)畫,并充當(dāng)所有其它動(dòng)畫函數(shù)的容器。HTML 模板可以綁定到 |
style()
|
定義一個(gè)或多個(gè)要用于動(dòng)畫中的 CSS 樣式。用于在動(dòng)畫期間控制 HTML 元素的視覺外觀。要使用對(duì)象語法。 |
?state() ? |
創(chuàng)建一組有名字的 CSS 樣式,它會(huì)在成功轉(zhuǎn)換到指定的狀態(tài)時(shí)應(yīng)用到元素上。該狀態(tài)可以在其它動(dòng)畫函數(shù)中通過名字進(jìn)行引用。 |
animate()
|
指定轉(zhuǎn)場的時(shí)序信息。 |
transition()
|
定義兩個(gè)命名狀態(tài)之間的動(dòng)畫序列。使用數(shù)組語法。 |
keyframes()
|
允許以特定的時(shí)間間隔對(duì)樣式進(jìn)行順序更改。用于 |
?group() ? |
指定要并行運(yùn)行的一組動(dòng)畫步驟(內(nèi)部動(dòng)畫)。該動(dòng)畫只有當(dāng)所有內(nèi)部動(dòng)畫步驟都完成之后才會(huì)繼續(xù)。用于 |
query()
|
找出當(dāng)前元素中的一個(gè)或多個(gè)內(nèi)部 HTML 元素。 |
sequence()
|
指定一個(gè)動(dòng)畫步驟列表,它們會(huì)逐個(gè)順序執(zhí)行。 |
stagger()
|
交錯(cuò)安排多元素動(dòng)畫的開始時(shí)間。 |
animation()
|
生成可在其它地方調(diào)用的可復(fù)用動(dòng)畫。與 |
useAnimation()
|
激活一個(gè)可復(fù)用動(dòng)畫。和 |
animateChild()
|
允許子組件上的動(dòng)畫和父組件在同一個(gè)時(shí)間范圍(timeframe)內(nèi)執(zhí)行。 |
更多建議: