新聞中心
動(dòng)畫轉(zhuǎn)場(chǎng)與觸發(fā)器
你已經(jīng)在簡(jiǎn)介頁(yè)學(xué)習(xí)了 Angular 動(dòng)畫的基礎(chǔ)知識(shí)。

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛(ài)。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶,將通過(guò)不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:域名注冊(cè)、網(wǎng)絡(luò)空間、營(yíng)銷軟件、網(wǎng)站建設(shè)、五華網(wǎng)站維護(hù)、網(wǎng)站推廣。
本章將深入講解特殊的轉(zhuǎn)場(chǎng)狀態(tài),如 ?*?(通配符)和 ?void?,并說(shuō)明這些特殊狀態(tài)如何作用于進(jìn)入或離開(kāi)視圖的元素。本章還探討了多重觸發(fā)器、動(dòng)畫回調(diào),以及使用關(guān)鍵幀技術(shù)的序列動(dòng)畫。
預(yù)定義狀態(tài)與通配符匹配
在 Angular 中,轉(zhuǎn)場(chǎng)狀態(tài)可以通過(guò) ?state()? 函數(shù)進(jìn)行顯式定義,或使用預(yù)定義的 ?*?(通配符)狀態(tài)和 ?void ?狀態(tài)。
通配符狀態(tài)
星號(hào) ?*? 或者叫通配符可以匹配任何一個(gè)動(dòng)畫狀態(tài)。它可用來(lái)定義那些不用在乎 HTML 元素的起始狀態(tài)或結(jié)束狀態(tài)的轉(zhuǎn)場(chǎng)動(dòng)畫。
比如,一個(gè) ?open => *? 轉(zhuǎn)場(chǎng)可應(yīng)用在當(dāng)元素的狀態(tài)從 ?open ?變成任何其它狀態(tài)時(shí)。
下面是通配符狀態(tài)的另一個(gè)代碼范例,以及我們以前使用 ?open ?和 ?closed ?狀態(tài)的實(shí)例。但這次,對(duì)于每個(gè)狀態(tài)到狀態(tài)的轉(zhuǎn)換對(duì),我們這次規(guī)定從任何狀態(tài)轉(zhuǎn)場(chǎng)到 ?closed ?狀態(tài)時(shí)要花 1 秒鐘,而從任何狀態(tài)轉(zhuǎn)場(chǎng)到 ?open ?狀態(tài)時(shí)要花 0.5 秒。
這讓我們可以添加新?tīng)顟B(tài),而不必把它手動(dòng)包含到每個(gè)單獨(dú)的轉(zhuǎn)場(chǎng)中。
animations: [
trigger('openClose', [
// ...
state('open', style({
height: '200px',
opacity: 1,
backgroundColor: 'yellow'
})),
state('closed', style({
height: '100px',
opacity: 0.8,
backgroundColor: 'blue'
})),
transition('* => closed', [
animate('1s')
]),
transition('* => open', [
animate('0.5s')
]),
]),
],使用雙向箭頭語(yǔ)法可以指定任意方向的狀態(tài)轉(zhuǎn)場(chǎng)。
transition('open <=> closed', [
animate('0.5s')
]),
使用帶多個(gè)轉(zhuǎn)場(chǎng)狀態(tài)的通配符狀態(tài)
在這個(gè)雙態(tài)按鈕的例子中,通配符不是很有用,因?yàn)橹挥袃煞N可能的狀態(tài):?open ?和 ?closed?。一般而言,當(dāng)一個(gè)特定狀態(tài)下的元素可能變更為多個(gè)潛在狀態(tài)時(shí),通配符狀態(tài)會(huì)更好用。如果我們的按鈕可以從 ?open ?變成 ?closed ?或類似 ?inProgress ?的狀態(tài),則可以使用通配符狀態(tài)來(lái)減少所需的編碼量。
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')
]),
transition('* => closed', [
animate('1s')
]),
transition('* => open', [
animate('0.5s')
]),
transition('open <=> closed', [
animate('0.5s')
]),
transition ('* => open', [
animate ('1s',
style ({ opacity: '*' }),
),
]),
transition('* => *', [
animate('1s')
]),當(dāng)在任意兩個(gè)狀態(tài)之間切換時(shí),?* => *? 轉(zhuǎn)場(chǎng)都會(huì)生效。
轉(zhuǎn)場(chǎng)會(huì)按照其定義的順序進(jìn)行匹配。因此,你可以在 ?* => *? 轉(zhuǎn)場(chǎng)的前面定義其它轉(zhuǎn)場(chǎng)。比如,定義只針對(duì) ?open => closed? 的狀態(tài)變更或動(dòng)畫,或 ?closed => open?,而使用 ?* => *? 作為匹配不上其它狀態(tài)對(duì)時(shí)的后備。
要這么做,只要把那些更特殊的轉(zhuǎn)場(chǎng)放在 ?* => *? 前面就行了。
使用帶樣式的通配符狀態(tài)
使用帶樣式的 ?*? 通配符來(lái)告訴動(dòng)畫使用當(dāng)前的狀態(tài)值,并用它進(jìn)行動(dòng)畫處理。通配符是一個(gè)后備值,如果未在觸發(fā)器中聲明動(dòng)畫狀態(tài),就會(huì)使用這個(gè)值。
transition ('* => open', [
animate ('1s',
style ({ opacity: '*' }),
),
]),
void 狀態(tài)
可以使用 ?void ?狀態(tài)來(lái)為進(jìn)入或離開(kāi)頁(yè)面的元素配置轉(zhuǎn)場(chǎng)。
組合使用通配符和 void 狀態(tài)
可以在轉(zhuǎn)場(chǎng)中組合使用通配符和 ?void ?狀態(tài),以觸發(fā)那些進(jìn)入和離開(kāi)頁(yè)面的動(dòng)畫:
- 當(dāng)元素離開(kāi)視圖時(shí),就會(huì)觸發(fā) ?
* => void? 轉(zhuǎn)場(chǎng),而不管它離開(kāi)前處于什么狀態(tài) - 當(dāng)元素進(jìn)入視圖時(shí),就會(huì)觸發(fā) ?
void => *? 轉(zhuǎn)場(chǎng),而不管它進(jìn)入時(shí)處于什么狀態(tài) - 通配符狀態(tài) ?
*? 會(huì)匹配任何狀態(tài) —— 包括 ?void?
播放進(jìn)入和離開(kāi)視圖時(shí)的動(dòng)畫
本節(jié)介紹如何為進(jìn)入和離開(kāi)頁(yè)面的元素設(shè)置動(dòng)畫。
添加一些新的行為:
- 當(dāng)你把一個(gè)英雄添加到英雄列表中時(shí),它看起來(lái)是從左側(cè)飛進(jìn)頁(yè)面的
- 當(dāng)你從列表中移除一個(gè)英雄時(shí),它看起來(lái)是從右側(cè)飛出去的
animations: [
trigger('flyInOut', [
state('in', style({ transform: 'translateX(0)' })),
transition('void => *', [
style({ transform: 'translateX(-100%)' }),
animate(100)
]),
transition('* => void', [
animate(100, style({ transform: 'translateX(100%)' }))
])
])
]在上述代碼中,當(dāng) HTML 元素沒(méi)有附著在視圖中時(shí),我們就會(huì)應(yīng)用 ?void ?狀態(tài)。
:enter 和 :leave 別名
?:enter? 和 ?:leave? 分別是 ?void => *? 和 ?* => void? 的別名。這些別名供多個(gè)動(dòng)畫函數(shù)使用。
transition ( ':enter', [ … ] ); // alias for void => *
transition ( ':leave', [ … ] ); // alias for * => void定位進(jìn)入視圖的元素更難,因?yàn)樗辉?nbsp;DOM 中。因此,使用別名 ?:enter? 和 ?:leave? 來(lái)定位要從視圖中插入或刪除的 HTML 元素。
和 :enter 與 :leave 一起使用 *ngIf 和 *ngFor
當(dāng)任何 ?*ngIf? 或 ?*ngFor? 中的視圖放進(jìn)頁(yè)面中時(shí),會(huì)運(yùn)行 ?:enter? 轉(zhuǎn)場(chǎng);當(dāng)移除這些視圖時(shí),就會(huì)運(yùn)行 ?:leave? 轉(zhuǎn)場(chǎng)。
注意:
進(jìn)入/離開(kāi)行為有時(shí)會(huì)令人困惑。作為經(jīng)驗(yàn)法則,考慮到 Angular 添加到 DOM 的任何元素都會(huì)通過(guò) ?
:enter? 轉(zhuǎn)換傳遞,但只有通過(guò) Angular 直接從 DOM 刪除的元素會(huì)通過(guò) ?
:leave? 轉(zhuǎn)換傳遞(例如,元素的視圖是從 DOM,因?yàn)槠涓讣?jí)正在從 DOM 中刪除或應(yīng)用程序的路由已更改,則元素將不會(huì)通過(guò) ?
:leave? 轉(zhuǎn)換)。
本例子中有一個(gè)名叫 ?myInsertRemoveTrigger ?的觸發(fā)器,來(lái)表示進(jìn)入和離開(kāi)動(dòng)畫。其 HTML 模板包含下列代碼。
The box is inserted
在組件文件中,?:enter? 轉(zhuǎn)場(chǎng)會(huì)將初始透明度設(shè)置為 0,然后設(shè)置動(dòng)畫,當(dāng)該元素已經(jīng)插入視圖中之后,把這個(gè)透明度設(shè)置為 1。
trigger('myInsertRemoveTrigger', [
transition(':enter', [
style({ opacity: 0 }),
animate('100ms', style({ opacity: 1 })),
]),
transition(':leave', [
animate('100ms', style({ opacity: 0 }))
])
]),請(qǐng)注意,此示例不需要使用?state()?。
轉(zhuǎn)場(chǎng)中的 :increment 和 :decrement
?transition()? 函數(shù)還能接受額外的選擇器值:?:increment? 和 ?:decrement?。當(dāng)數(shù)值增加或減小時(shí),使用這些來(lái)啟動(dòng)轉(zhuǎn)場(chǎng)。
trigger('filterAnimation', [
transition(':enter, * => 0, * => -1', []),
transition(':increment', [
query(':enter', [
style({ opacity: 0, width: 0 }),
stagger(50, [
animate('300ms ease-out', style({ opacity: 1, width: '*' })),
]),
], { optional: true })
]),
transition(':decrement', [
query(':leave', [
stagger(50, [
animate('300ms ease-out', style({ opacity: 0, width: 0 })),
]),
])
]),
]),
轉(zhuǎn)場(chǎng)中的邏輯值
如果某個(gè)觸發(fā)器以邏輯型的值作為綁定值,那么就可以使用能與 ?true ?和 ?false? 或 1 和 0 相比較的 ?transition()? 表達(dá)式來(lái)匹配這個(gè)值。
在上述代碼片段中,HTML 模板將 ? 在組件代碼中,? 你可以為組件定義多個(gè)動(dòng)畫觸發(fā)器并將這些動(dòng)畫觸發(fā)器附著到不同的元素上,這些元素之間的父子關(guān)系會(huì)影響動(dòng)畫的運(yùn)行方式和時(shí)機(jī)。 每次在 Angular 中觸發(fā)動(dòng)畫時(shí),父動(dòng)畫始終會(huì)優(yōu)先,而子動(dòng)畫會(huì)被阻塞。為了運(yùn)行子動(dòng)畫,父動(dòng)畫必須查詢出包含子動(dòng)畫的每個(gè)元素,然后使用 ? 可以把一個(gè)名叫 ? 下面的代碼范例展示了如何使用此特性。 The box is now {{ isOpen ? 'Open' : 'Closed' }}! 當(dāng) ? 當(dāng) HTML 模板中的某個(gè)元素使用 ? 不過(guò),選擇性的子動(dòng)畫仍然可以用如下方式之一在已禁用的父元素上運(yùn)行: 要禁用 Angular 應(yīng)用中的所有動(dòng)畫,只要把 ?
注意: 當(dāng)動(dòng)畫啟動(dòng)和終止時(shí),? 在 HTML 模板中,動(dòng)畫事件可以通過(guò) ? 動(dòng)畫回調(diào)的潛在用途之一,是用來(lái)覆蓋比較慢的 API 調(diào)用,比如查閱數(shù)據(jù)庫(kù)。比如,你可以建立一個(gè) InProgress 按鈕,讓它擁有自己的循環(huán)動(dòng)畫。當(dāng)后端系統(tǒng)操作完成時(shí),它會(huì)播放脈動(dòng)效果或其它一些視覺(jué)動(dòng)作。 然后,在當(dāng)前動(dòng)畫結(jié)束時(shí),可以調(diào)用另一個(gè)動(dòng)畫。比如,當(dāng) API 調(diào)用完成時(shí),按鈕會(huì)從 ? 動(dòng)畫可以影響最終用戶,讓他覺(jué)得操作更快 —— 雖然并沒(méi)有。因此,簡(jiǎn)單的動(dòng)畫是保持用戶滿意的一種經(jīng)濟(jì)有效的手段,而不必尋求提高服務(wù)器調(diào)用的速度或被迫補(bǔ)救那些你無(wú)法控制的情況,比如不可靠的網(wǎng)絡(luò)連接。 回調(diào)可以作為調(diào)試工具,比如與 ? 前一節(jié)是簡(jiǎn)單的雙態(tài)轉(zhuǎn)場(chǎng)?,F(xiàn)在,我們要使用關(guān)鍵幀動(dòng)畫創(chuàng)建一個(gè)具有多個(gè)順序執(zhí)行步驟的動(dòng)畫。 Angular 的 ? 這些更改顏色的代碼如下所示。 關(guān)鍵幀包括一個(gè)用來(lái)定義動(dòng)畫中每個(gè)樣式何時(shí)開(kāi)始更改的偏移(offset)屬性。偏移是個(gè) 0 到 1 之間的相對(duì)值,分別標(biāo)記動(dòng)畫的開(kāi)始和結(jié)束時(shí)間,并且只要使用了它,就要同樣應(yīng)用于這個(gè)關(guān)鍵幀的每個(gè)步驟。 定義關(guān)鍵幀的偏移量是可選的。如果省略它們,就會(huì)自動(dòng)分配均勻間隔的偏移。比如,三個(gè)沒(méi)有預(yù)定義偏移的關(guān)鍵幀會(huì)分別使用 0、0.5、1 作為偏移。在上面的例子中,還可以為中間的轉(zhuǎn)場(chǎng)指定偏移量 0.8。代碼如下。 帶有指定偏移量的代碼如下。 你可以在單個(gè)動(dòng)畫中組合使用 ? 通過(guò)在整個(gè)動(dòng)畫中定義特定偏移處的樣式,可以使用關(guān)鍵幀在動(dòng)畫中創(chuàng)建脈動(dòng)效果。 下面是使用關(guān)鍵幀創(chuàng)建脈動(dòng)效果的例子: 此動(dòng)畫的代碼片段是這樣的。 Angular 的動(dòng)畫支持是基于 Web 動(dòng)畫的,所以你可以動(dòng)瀏覽器認(rèn)為可動(dòng)(animatable)的任意屬性。包括位置、大小、變形、顏色、邊框等。W3C 在 CSS 轉(zhuǎn)場(chǎng)頁(yè)也維護(hù)了一個(gè)可動(dòng)屬性的列表。 對(duì)于帶有數(shù)值的位置屬性,可以把值作為字符串(別忘了帶引號(hào))并使用適當(dāng)?shù)暮缶Y來(lái)定義其單位: 你還可以用數(shù)字形式提供這個(gè)值(不帶單位),這種情況下,Angular 假設(shè)默認(rèn)的單位是像素(?
注意: 有時(shí)你在運(yùn)行之前并不知道某個(gè)樣式的屬性值。比如,元素的寬度和高度通常取決于其內(nèi)容和屏幕大小。在使用 CSS 動(dòng)畫時(shí),這些屬性通常會(huì)具有挑戰(zhàn)性(譯注:因?yàn)?nbsp;CSS 動(dòng)畫不支持自動(dòng)確定寬高)。 這些情況下,你可以在 ? 下面的例子中有一個(gè)名叫 ? Angular 中的 ?openClose ?的觸發(fā)器,其狀態(tài)表達(dá)式是 ?isOpen?,可能的值為 ?true ?和 ?false?。這種模式可以代替創(chuàng)建兩個(gè)命名狀態(tài) ?open ?和 ?close ?的方式。@Component? 元數(shù)據(jù)下的 ?animations:? 屬性中,當(dāng)該狀態(tài)求值為 ?true? 時(shí)(這里表示 "open"),相關(guān) HTML 元素的高度值為通配符樣式 ?*? 或某個(gè)默認(rèn)值。在這種情況下,它會(huì)使用此元素開(kāi)始動(dòng)畫前的現(xiàn)有高度。當(dāng)該元素是 "closed" 時(shí),它的高度會(huì)從指定的高度運(yùn)動(dòng)到 0,這會(huì)讓它不可見(jiàn)。animations: [
trigger('openClose', [
state('true', style({ height: '*' })),
state('false', style({ height: '0px' })),
transition('false <=> true', animate(500))
])
],多重動(dòng)畫觸發(fā)器
父-子動(dòng)畫
animateChild()? 函數(shù)來(lái)運(yùn)行它們。在某個(gè) HTML 元素上禁用動(dòng)畫
@.disabled? 的動(dòng)畫控制綁定放在 HTML 元素上,以禁用該元素及其子元素上的動(dòng)畫。當(dāng) ?@.disabled? 綁定為 ?true ?時(shí),就會(huì)禁止渲染所有動(dòng)畫。@Component({
animations: [
trigger('childAnimation', [
// ...
]),
],
})
export class OpenCloseChildComponent {
isDisabled = false;
isOpen = false;
}@.disabled? 綁定為 ?true ?時(shí),?@childAnimation? 觸發(fā)器就不會(huì)啟動(dòng)。@.disabled? 禁止了動(dòng)畫時(shí),也會(huì)同時(shí)禁止其所有內(nèi)部元素的動(dòng)畫。你無(wú)法有選擇的單獨(dú)禁用單個(gè)元素上的多個(gè)動(dòng)畫。query()? 函數(shù)來(lái)收集 HTML 模板中位于禁止動(dòng)畫區(qū)域內(nèi)部的元素。這些元素仍然可以播放動(dòng)畫。 animateChild()? 來(lái)播放它。禁用所有動(dòng)畫
@.disabled? 綁定放在頂層的 Angular 組件上即可。@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css'],
animations: [
slideInAnimation
]
})
export class AppComponent {
@HostBinding('@.disabled')
public animationsDisabled = false;
}
禁用應(yīng)用級(jí)的動(dòng)畫在端到端(E2E)測(cè)試中是很有用的。
動(dòng)畫回調(diào)
trigger()? 函數(shù)會(huì)發(fā)出一些回調(diào)。在下面的例子中,我們有一個(gè)包含 ?openClose ?觸發(fā)器的組件。@Component({
selector: 'app-open-close',
animations: [
trigger('openClose', [
// ...
]),
],
templateUrl: 'open-close.component.html',
styleUrls: ['open-close.component.css']
})
export class OpenCloseComponent {
onAnimationEvent(event: AnimationEvent) {
}
}$event? 傳遞回來(lái),比如 ?@triggerName.start? 和 ?@triggerName.done?,這里的 ?triggerName ?表示所使用的觸發(fā)器名字。在我們的例子中,?openClose ?觸發(fā)器將會(huì)是這樣的。inProgress ?狀態(tài)變成 ?closed ?狀態(tài)。console.warn()? 結(jié)合使用,以便在瀏覽器的開(kāi)發(fā)者控制臺(tái)中查看應(yīng)用的進(jìn)度。下列代碼片段為我們?cè)嫉碾p態(tài)按鈕(?open ?與 ?closed?)范例創(chuàng)建了控制臺(tái)輸出。export class OpenCloseComponent {
onAnimationEvent(event: AnimationEvent) {
// openClose is trigger name in this example
console.warn(`Animation Trigger: ${event.triggerName}`);
// phaseName is "start" or "done"
console.warn(`Phase: ${event.phaseName}`);
// in our example, totalTime is 1000 (number of milliseconds in a second)
console.warn(`Total time: ${event.totalTime}`);
// in our example, fromState is either "open" or "closed"
console.warn(`From: ${event.fromState}`);
// in our example, toState either "open" or "closed"
console.warn(`To: ${event.toState}`);
// the HTML element itself, the button in this case
console.warn(`Element: ${event.element}`);
}
}關(guān)鍵幀動(dòng)畫
keyframe()? 函數(shù)類似于 CSS 中的關(guān)鍵幀。關(guān)鍵幀允許在單個(gè)時(shí)間段內(nèi)進(jìn)行多種樣式更改。比如,我們的按鈕可以在單個(gè)的 2 秒時(shí)間段內(nèi)多次改變顏色,而不是漸隱掉。transition('* => active', [
animate('2s', keyframes([
style({ backgroundColor: 'blue' }),
style({ backgroundColor: 'red' }),
style({ backgroundColor: 'orange' })
]))偏移
transition('* => active', [
animate('2s', keyframes([
style({ backgroundColor: 'blue', offset: 0}),
style({ backgroundColor: 'red', offset: 0.8}),
style({ backgroundColor: '#754600', offset: 1.0})
])),
]),
transition('* => inactive', [
animate('2s', keyframes([
style({ backgroundColor: '#754600', offset: 0}),
style({ backgroundColor: 'red', offset: 0.2}),
style({ backgroundColor: 'blue', offset: 1.0})
]))
]),duration?、?delay ?和 ?easing ?來(lái)定義關(guān)鍵幀。帶脈動(dòng)效果的關(guān)鍵幀
open ?和 ?closed ?狀態(tài)(包括其原始的高度、顏色和透明度)會(huì)在一秒鐘內(nèi)逐漸發(fā)生變化。 trigger('openClose', [
state('open', style({
height: '200px',
opacity: 1,
backgroundColor: 'yellow'
})),
state('close', style({
height: '100px',
opacity: 0.5,
backgroundColor: 'green'
})),
// ...
transition('* => *', [
animate('1s', keyframes ( [
style({ opacity: 0.1, offset: 0.1 }),
style({ opacity: 0.6, offset: 0.2 }),
style({ opacity: 1, offset: 0.5 }),
style({ opacity: 0.2, offset: 0.7 })
]))
])
])可動(dòng)的屬性與單位
'50px' ?'3em' ?'100%' ?px?)。把 50 像素表示為 ?50 ?和 ?'50px'? 是一樣的。
字符串形式的 ?
"50"? 是無(wú)效的。
使用通配符自動(dòng)計(jì)算屬性
style()? 中指定通配符 ?*? 屬性,以便在運(yùn)行期間計(jì)算該屬性的值,然后把它插入到動(dòng)畫中。shrinkOut ?的觸發(fā)器,它會(huì)在 HTML 元素離開(kāi)頁(yè)面時(shí)使用。該動(dòng)畫會(huì)使用它離開(kāi)之前的任意高度,并從該高度動(dòng)畫到 0。animations: [
trigger('shrinkOut', [
state('in', style({ height: '*' })),
transition('* => void', [
style({ height: '*' }),
animate(250, style({ height: 0 }))
])
])
]關(guān)鍵幀動(dòng)畫總結(jié)
keyframes()? 函數(shù)允許你在單個(gè)轉(zhuǎn)場(chǎng)中指定多個(gè)臨時(shí)樣式,并使用可選的 ?offset ?來(lái)定義動(dòng)畫中每次樣式變化的發(fā)生時(shí)機(jī)。
網(wǎng)站欄目:創(chuàng)新互聯(lián)Angular教程:Angular轉(zhuǎn)場(chǎng)與觸發(fā)器
網(wǎng)頁(yè)路徑:http://m.5511xx.com/article/cohhsjj.html


咨詢
建站咨詢
