使用Angular4動畫爲頁面添彩

原文:Angular — Supercharge your Router transitions using new animation features (v4.3+)javascript

首先咱們看一下效果展現的demohtml

Basicjava

Variationgit

Staggergithub

Finalweb

樣例

爲了介紹這個新的動畫,咱們將用一個只有home和about頁面的簡單應用來作演示。咱們將要用內容向左飛出而後用下圖所示的交錯進入的效果實現一個很酷的路由頁面切換bootstrap

gif1

動畫依賴安裝

獨立引入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動畫。Angular是基於最新的Web Animations API,咱們使用動畫觸發器(animation triggers)來定義一系列狀態和變換屬性。咱們也能夠用CSS樣式來改寫實現咱們想要的效果

主要的原則是開始和結尾的動畫樣式由咱們自定義,中間變換的計算過程交給工具自己

gif2

固然,能夠經過設置時間來設置中間動畫,好比1s,1.2s,200ms。其餘的就是你們熟悉的CSS動畫的速度屬性好比easelinerease-in-out

而Angular 4.2以上的版本里咱們能夠用順序(sequence)和組合(group)來讓動畫一個接一個執行仍是同時執行;查詢(query)能夠操做子元素而交錯(stagger)能夠創造一個很棒的連鎖效果

這些事件將觸發一個動畫:

  • 向或者從視圖裏裝載或者卸載一個元素
  • 改變已綁定觸發器的狀態 好比:[@routerTransition]="home"

在路由轉換的先後關係中,要注意,組件正在被移除並做爲導航的一部分被添加到視圖中的過程。

定義動畫

首先讓咱們看一下如何使用Angular動畫來讓內容向左滑出

![gif3](https://cdn-images-1.medium.com/max/1600/1*b5897deHacTSCWgL2WGvHg.gif)

最初,定義咱們的觸發器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

注意這種實現方式與咱們將觸發器綁定到咱們想要動畫的元素的動畫中的用例不一樣。
這意味着咱們不能使用狀態來對路由組件進行樣式,由於這樣能夠將樣式應用於父結點(咱們的示例中的主元素),而不是路由組件。

在路由初始化期間,一些查詢指令會返回空的結果,爲了不拋出錯誤,咱們在全部查詢中設置了可選參數。

加上交錯動畫

一旦咱們的基礎部分完成了,咱們能夠很容易在這個基礎上用查詢和交錯控制加上一些新的效果

gif4

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組件的代碼而且也加入了貝塞爾曲線來優化路徑,最後效果以下圖

![gif4](https://cdn-images-1.medium.com/max/1600/1*giXV5gUOKltllHG83PufoQ.gif)

相關文章
相關標籤/搜索