原文:Angular — Supercharge your Router transitions using new animation features (v4.3+)javascript
首先咱們看一下效果展現的demohtml
Basicjava
Variationgit
Staggergithub
Finalweb
爲了介紹這個新的動畫,咱們將用一個只有home和about頁面的簡單應用來作演示。咱們將要用內容向左飛出而後用下圖所示的交錯進入的效果實現一個很酷的路由頁面切換bootstrap
獨立引入Angular 4裏的動畫部分,這樣可使你的項目更輕便,若是你不想用動畫的話只要直接拿掉就能夠了後端
首先,咱們把下列依賴獨立引入你的項目:@angular/animations
和 @angular/platform-browser/animations
接下來在項目中的入口模塊的代碼引入 BrowserAnimationsModule
數組
\\app.module.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @NgModule({ imports: [ BrowserModule, BrowserAnimationsModule, ... ], declarations: [ App, ... ], bootstrap: [ App ] }) export class AppModule { }
若是你須要使用 不支持原生WEB動畫API的瀏覽器 的話:好比IE、Edge、Safari等等。你必需要引入web-animations依賴瀏覽器
正如咱們所見,咱們的例子將由頂部導航和主體內容部分組成。各個內容部分將共享同一個導航欄,咱們使用router-outlet
元素來通知路由咱們須要渲染組件的地方和須要匹配路由的地方
\\app.module.ts @Component({ selector: 'my-app', template: ` <nav> <a routerLink="/home" routerLinkActive="active">Home</a> <a routerLink="/about" routerLinkActive="active">About</a> </nav> <main> <router-outlet></router-outlet> </main> ` }) export class App { }
咱們使用靜態路由來建立不一樣的導航連接。而後咱們用routerLinkActive
指令來裝飾當前的內容部分。舉個例子,若是咱們要導航到首頁Home,導航連接的標籤上將加上active
選擇器並根據這個渲染對應部分
<a href="#/home" class="active">Home</a>
讓咱們改變默認的路由變換設置。首先咱們須要加上動畫觸發器屬性 routerTransition
,而後咱們綁定@routerTransition
在主標籤元素上,以後,咱們能夠裝飾內部的路由組件並交由Angular的路由來實例化
咱們能夠用一個div或者其餘標籤來替換主標籤元素,只要它是
router-outlet
的父結點
咱們用getState
方法傳遞外部設置的參數來設置正確的狀態。這個方法將返回一個 state
的用於設置路由定義的屬性。咱們接下來看下一個部分,這個設置將容許咱們去控制每一個路由將執行哪一種切換
提示:咱們能夠經過使用
#o="outlet"
來得到外部傳參,因爲在router-outlet definition裏使用exportAs使之成爲可能。這給了咱們一個快速獲取底層RouterOutlet選擇器類的途徑
\\app.module.ts @Component({ selector: 'my-app', animations: [ routerTransition ], template: ` <main [@routerTransition]="getState(o)"> <router-outlet #o="outlet"></router-outlet> </main> ` }) export class App { getState(outlet) { return outlet.activatedRouteData.state; } }
在Angular裏面,路由會去嘗試匹配路由定義和當前的url,同一個生效的配置優先級由上到下
\\app.routing.ts const routes = [ { path: '', redirectTo: 'home', pathMatch: 'full' }, { path: 'home', component: Home, data: { state: 'home' } }, { path: 'about', component: About, data: { state: 'about' } }, { path: '**', component: NotFound } ]; export const AppRouting = RouterModule.forRoot(routes, { useHash: true });
路由設置告訴路由當匹配到Home和About頁面的路徑時去實例化對應的組件。注意這個data
屬性設置每一個狀態給對應的路由。這些狀態將要去匹配咱們在routerTransition
中設置的切換
咱們也須要設置兩個爲了一般展現的特殊路由。這個空路徑的路由將提供一個默重定向到主頁的路由以防導航去了一個非咱們須要的路徑。其餘的路由或者未定義的路由展現一個用戶友好的404頁面就好
爲了這個例子,由於Plunker的緣由咱們使用一個哈希定位的策略。若是咱們須要後端咱們能夠沿用普通的路徑跳轉,可是若是沒有後端來展現404錯誤的話咱們就使用這個策略來重定向未知路徑到index.html
讓咱們隆重介紹Angular動畫。Angular是基於最新的Web Animations API,咱們使用動畫觸發器(animation triggers)來定義一系列狀態和變換屬性。咱們也能夠用CSS樣式來改寫實現咱們想要的效果
主要的原則是開始和結尾的動畫樣式由咱們自定義,中間變換的計算過程交給工具自己
固然,能夠經過設置時間來設置中間動畫,好比1s,1.2s,200ms。其餘的就是你們熟悉的CSS動畫的速度屬性好比ease
、liner
和ease-in-out
。
而Angular 4.2以上的版本里咱們能夠用順序(sequence)和組合(group)來讓動畫一個接一個執行仍是同時執行;查詢(query)能夠操做子元素而交錯(stagger)能夠創造一個很棒的連鎖效果
這些事件將觸發一個動畫:
[@routerTransition]="home"
在路由轉換的先後關係中,要注意,組件正在被移除並做爲導航的一部分被添加到視圖中的過程。
首先讓咱們看一下如何使用Angular動畫來讓內容向左滑出
最初,定義咱們的觸發器routerTransition
。在這個實現中,咱們使用了一個覆蓋全部可能狀態的通用轉換
這是個經過兩個獨立轉換* => home
、 * => about
完成的重寫
咱們能夠在咱們的轉換中用兩個特殊標識
void
和*
來表明:一個元素還沒有被掛載到視圖或者任何狀態
\\router.animations.ts import {trigger, animate, style, group, animateChild, query, stagger, transition} from '@angular/animations'; export const routerTransition = trigger('routerTransition', [ transition('* <=> *', [ /* order */ /* 1 */ query(':enter, :leave', style({ position: 'fixed', width:'100%' }) , { optional: true }), /* 2 */ group([ // block executes in parallel query(':enter', [ style({ transform: 'translateX(100%)' }), animate('0.5s ease-in-out', style({ transform: 'translateX(0%)' })) ], { optional: true }), query(':leave', [ style({ transform: 'translateX(0%)' }), animate('0.5s ease-in-out', style({ transform: 'translateX(-100%)' } ], { optional: true }), ]) ]) ])
咱們在第二個參數裏定義了一個順序執行通用轉換的數組 。第一個參數呢,使用了一個新的查詢指令去選擇新的路徑組件和離開的組件;查詢指令可使用相似CSS僞類的選擇器方式選中,好比一些特殊的關鍵詞::enter
,:leave
和*
在第一次查詢中,:enter
和:leave
將會匹配被掛載和卸載的組件,多個選擇器用逗號分開。一旦咱們有了這些路由組件,咱們能夠設置他們的樣式去達到滑動的效果。使用 { position: fixed }
組件將根據視口放置,並滑過頁面。
接下來,咱們將設置一個組合使得內部動畫同時執行。
讓咱們想象一下,咱們從Home切換到About頁面,第一次查詢將會匹配這個被加了:enter
的組件,那就是About組件。咱們首先在右邊很遠的地方設置動畫,而後讓它緩緩的進入滑動到固定的位置。結果就是About組件從右邊滑到左邊。第二次查詢中,咱們用了一個類似的路徑,使用:leave
來匹配一樣在左邊很遠處的Home組件
CSS小提示:爲了更好的表現,咱們使用transform取代top,bottom,left,right
注意這種實現方式與咱們將觸發器綁定到咱們想要動畫的元素的動畫中的用例不一樣。
這意味着咱們不能使用狀態來對路由組件進行樣式,由於這樣能夠將樣式應用於父結點(咱們的示例中的主元素),而不是路由組件。
在路由初始化期間,一些查詢指令會返回空的結果,爲了不拋出錯誤,咱們在全部查詢中設置了可選參數。
一旦咱們的基礎部分完成了,咱們能夠很容易在這個基礎上用查詢和交錯控制加上一些新的效果
export const routerTransition = trigger('routerTransition', [ transition('* <=> *', [ /* order */ /* 1 */ query(':enter, :leave', ...), /* 2 */ query('.block', style({ opacity: 0 })), /* 3 */ group([ // block executes in parallel query(':enter', [...]), query(':leave', [...]), ]), /* 4 */ query(':enter .block', stagger(400, [ style({ transform: 'translateY(100px)' }), animate('1s ease-in-out', style({ transform: 'translateY(0px)', opacity: 1 })), ])), ]) ])
最終,咱們使用轉換(transform)和透明(opacity)來垂直向上滑動進入並淡入。
經過使用交錯,咱們爲每一個動畫引入了一個小的延遲(以毫秒爲單位),建立了一個很好的窗簾效果。最後一點,咱們不得不引入一個新的查詢,用(opacity:0)初始化.block元素,這樣當組件滑入時就不會顯示。
做爲最終的潤色,我添加了一些反向交錯離開Home組件的代碼而且也加入了貝塞爾曲線來優化路徑,最後效果以下圖