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