W3Cschool
恭喜您成為首批注冊用戶
獲得88經驗值獎勵
對下列概念有基本的理解:
路由能讓用戶在應用中的不同路由之間導航。當用戶從一個路由導航到另一個路由時,Angular 路由器會把這個 URL 映射到一個相關的組件,并顯示其視圖。為這種路由轉換添加動畫,將極大地提升用戶體驗。
Angular 路由器天生帶有高級動畫功能,它可以讓你為在路由變化時為視圖之間設置轉場動畫。要想在路由切換時生成動畫序列,你需要首先定義出嵌套的動畫序列。從宿主視圖的頂層組件開始,在這些內嵌視圖的宿主組件中嵌套添加其它動畫。
要啟用路由轉場動畫,需要做如下步驟:
讓我們以兩個路由之間的導航過程來解釋一下路由轉場動畫,Home 和 About 分別與 ?HomeComponent
?和 ?AboutComponent
?的視圖相關聯(lián)。所有這些組件視圖都是頂層視圖的子節(jié)點,其宿主是 ?AppComponent
?。我們將實現(xiàn)路由器過渡動畫,該動畫會在出現(xiàn)新視圖時向右滑動,并當用戶在兩個路由之間導航時把舊視圖滑出。
首先,使用 ?RouterModule
?類提供的方法來配置一組路由。該路由配置會告訴路由器該如何導航。
使用 ?RouterModule.forRoot
? 方法來定義一組路由。同時,把其返回值添加到主模塊 ?AppModule
?的 ?imports
?數(shù)組中。
注意:
在根模塊 ?AppModule
?中使用 ?RouterModule.forRoot
? 方法來注冊一些頂層應用路由和提供者。對于特性模塊,則改用 ?RouterModule.forChild
? 方法。
下列配置定義了應用程序中可能的路由。
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterModule } from '@angular/router';
import { AppComponent } from './app.component';
import { OpenCloseComponent } from './open-close.component';
import { OpenClosePageComponent } from './open-close-page.component';
import { OpenCloseChildComponent } from './open-close.component.4';
import { ToggleAnimationsPageComponent } from './toggle-animations-page.component';
import { StatusSliderComponent } from './status-slider.component';
import { StatusSliderPageComponent } from './status-slider-page.component';
import { HeroListPageComponent } from './hero-list-page.component';
import { HeroListGroupPageComponent } from './hero-list-group-page.component';
import { HeroListGroupsComponent } from './hero-list-groups.component';
import { HeroListEnterLeavePageComponent } from './hero-list-enter-leave-page.component';
import { HeroListEnterLeaveComponent } from './hero-list-enter-leave.component';
import { HeroListAutoCalcPageComponent } from './hero-list-auto-page.component';
import { HeroListAutoComponent } from './hero-list-auto.component';
import { HomeComponent } from './home.component';
import { AboutComponent } from './about.component';
import { InsertRemoveComponent } from './insert-remove.component';
import { QueryingComponent } from './querying.component';
@NgModule({
imports: [
BrowserModule,
BrowserAnimationsModule,
RouterModule.forRoot([
{ path: '', pathMatch: 'full', redirectTo: '/enter-leave' },
{
path: 'open-close',
component: OpenClosePageComponent,
data: { animation: 'openClosePage' }
},
{
path: 'status',
component: StatusSliderPageComponent,
data: { animation: 'statusPage' }
},
{
path: 'toggle',
component: ToggleAnimationsPageComponent,
data: { animation: 'togglePage' }
},
{
path: 'heroes',
component: HeroListPageComponent,
data: { animation: 'filterPage' }
},
{
path: 'hero-groups',
component: HeroListGroupPageComponent,
data: { animation: 'heroGroupPage' }
},
{
path: 'enter-leave',
component: HeroListEnterLeavePageComponent,
data: { animation: 'enterLeavePage' }
},
{
path: 'auto',
component: HeroListAutoCalcPageComponent,
data: { animation: 'autoPage' }
},
{
path: 'insert-remove',
component: InsertRemoveComponent,
data: { animation: 'insertRemovePage' }
},
{
path: 'querying',
component: QueryingComponent,
data: { animation: 'queryingPage' }
},
{
path: 'home',
component: HomeComponent,
data: { animation: 'HomePage' }
},
{
path: 'about',
component: AboutComponent,
data: { animation: 'AboutPage' }
},
])
],
?home
?和 ?about
?路徑分別關聯(lián)著 ?HomeComponent
?和 ?AboutComponent
?視圖。該路由配置告訴 Angular 路由器當導航匹配了相應的路徑時,就實例化 ?HomeComponent
?和 ?AboutComponent
?視圖。
除了 ?path
?、?component
?之外,每個路由定義中的 ?data
?屬性也定義了與此路由有關的動畫配置。當路由變化時,?data
?屬性的值就會傳給 ?AppComponent
?。你還可以在路由配置中傳遞其它的值供路由的動畫使用。?data
?屬性的值必須滿足 ?routeAnimation
? 中定義的轉場動畫的要求,稍后我們就會定義它。
注意:
這個 ?data
?中的屬性名可以是任意的。比如,上面例子中使用的名字 animation 就是隨便起的。
配置好路由之后,還要告訴 Angular 路由器當路由匹配時,要把視圖渲染到那里。你可以通過在根組件 ?AppComponent
?的模板中插入一個 ?<router-outlet>
? 容器來指定路由出口的位置。
?ChildrenOutletContexts
?包含有關插座和激活路由的信息。我們可以用每個 ?Route
?的 ?data
?屬性來為我們的路由轉換設置動畫。
<div [@routeAnimations]="getRouteAnimationData()">
<router-outlet></router-outlet>
</div>
?AppComponent
?中定義了一個可以檢測視圖何時發(fā)生變化的方法,該方法會基于路由配置的 ?data
?屬性值,將動畫狀態(tài)值賦值給動畫觸發(fā)器(?@routeAnimation
?)。下面就是一個 ?AppComponent
?中的范例方法,用于檢測路由在何時發(fā)生了變化。
constructor(private contexts: ChildrenOutletContexts) {}
getRouteAnimationData() {
return this.contexts.getContext('primary')?.route?.snapshot?.data?.['animation'];
}
這里的 ?getRouteAnimationData()
? 方法會獲取這個 outlet 指令的值(通過 ?#outlet="outlet"
?),并根據當前活動路由的自定義數(shù)據返回一個表示動畫狀態(tài)的字符串值??梢杂眠@個數(shù)據來控制各個路由之間該執(zhí)行哪個轉場。
動畫可以直接在組件中定義。對于此范例,我們會在獨立的文件中定義動畫,這讓我們可以復用這些動畫。
下面的代碼片段定義了一個名叫 ?slideInAnimation
?的可復用動畫。
export const slideInAnimation =
trigger('routeAnimations', [
transition('HomePage <=> AboutPage', [
style({ position: 'relative' }),
query(':enter, :leave', [
style({
position: 'absolute',
top: 0,
left: 0,
width: '100%'
})
]),
query(':enter', [
style({ left: '-100%' })
]),
query(':leave', animateChild()),
group([
query(':leave', [
animate('300ms ease-out', style({ left: '100%' }))
]),
query(':enter', [
animate('300ms ease-out', style({ left: '0%' }))
]),
]),
]),
transition('* <=> *', [
style({ position: 'relative' }),
query(':enter, :leave', [
style({
position: 'absolute',
top: 0,
left: 0,
width: '100%'
})
]),
query(':enter', [
style({ left: '-100%' })
]),
query(':leave', animateChild()),
group([
query(':leave', [
animate('200ms ease-out', style({ left: '100%', opacity: 0 }))
]),
query(':enter', [
animate('300ms ease-out', style({ left: '0%' }))
]),
query('@*', animateChild())
]),
])
]);
該動畫定義做了如下事情:
query()
? 來確定哪個子視圖正在進入或離開宿主視圖路由的變化會激活這個動畫觸發(fā)器,并應用一個與該狀態(tài)變更相匹配的轉場
注意:
這些轉場狀態(tài)必須和路由配置中定義的 ?data
?屬性的值相一致。
通過將可復用動畫 ?slideInAnimation
?添加到 ?AppComponent
?的 ?animations
?元數(shù)據中,可以讓此動畫定義能用在你的應用中。
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css'],
animations: [
slideInAnimation
]
})
那么,我們來分解一下這個動畫定義,并仔細看看它做了什么……
在轉場期間,新視圖將直接插入在舊視圖后面,并且這兩個元素會同時出現(xiàn)在屏幕上。要防止這種行為,就要修改宿主視圖,改用相對定位。然后,把已移除或已插入的子視圖改用絕對定位。在這些視圖中添加樣式,就可以讓容器就地播放動畫,并防止某個視圖影響頁面中其它視圖的位置。
trigger('routeAnimations', [
transition('HomePage <=> AboutPage', [
style({ position: 'relative' }),
query(':enter, :leave', [
style({
position: 'absolute',
top: 0,
left: 0,
width: '100%'
})
]),
使用 ?query()
? 方法可以找出當前宿主組件中的動畫元素。?query(":enter")
? 語句會返回已插入的視圖,?query(":leave")
? 語句會返回已移除的視圖。
假設你正在從 Home 轉場到 About,?Home => About
?。
query(':enter', [
style({ left: '-100%' })
]),
query(':leave', animateChild()),
group([
query(':leave', [
animate('300ms ease-out', style({ left: '100%' }))
]),
query(':enter', [
animate('300ms ease-out', style({ left: '0%' }))
]),
]),
]),
transition('* <=> *', [
style({ position: 'relative' }),
query(':enter, :leave', [
style({
position: 'absolute',
top: 0,
left: 0,
width: '100%'
})
]),
query(':enter', [
style({ left: '-100%' })
]),
query(':leave', animateChild()),
group([
query(':leave', [
animate('200ms ease-out', style({ left: '100%', opacity: 0 }))
]),
query(':enter', [
animate('300ms ease-out', style({ left: '0%' }))
]),
query('@*', animateChild())
]),
])
在設置了視圖的樣式之后,動畫代碼會執(zhí)行如下操作:
query(':enter style({ left: '-100%'})
? 會匹配添加的視圖,并通過將其定位在最左側來隱藏這個新視圖。animateChild()
?,來運行其子動畫。group()
?函數(shù)使內部動畫并行運行。group()
? 函數(shù)中:此動畫將導致 ?about
?視圖從左側劃入。
animateChild()
? 方法,以運行其子動畫。
你現(xiàn)在有了一個基本的路由動畫,可以在從一個視圖路由到另一個視圖時播放動畫。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: