Angular Route導(dǎo)航
路由基礎(chǔ)知識(shí)
路由相關(guān)對象介紹
名稱 | 簡介 |
---|---|
Routes | 路由配置定嗓,保存著哪個(gè)URL對應(yīng)展示哪個(gè)組件敦姻,以及在哪個(gè)RouterOutlet中展示組件秉馏。 |
RouterOutlet | 在Html中標(biāo)記路由內(nèi)容呈現(xiàn)位置的占位符指令搪桂。 |
Router | 負(fù)責(zé)在運(yùn)行時(shí)執(zhí)行路由的對象康谆,可以通過調(diào)用其navigate()和navigateByUrl()方法來導(dǎo)航到一個(gè)指定的路由赐劣。 |
RouterLink | 在Html中聲明路由導(dǎo)航用的指令柄慰。 |
ActivatedRoute | 當(dāng)前激活的路由對象鳍悠,保存著當(dāng)前路由的信息,如路由地址坐搔,路由參數(shù)等藏研。 |
新建路由項(xiàng)目
使用angular-cli
新建項(xiàng)目。
ng new router --routing
新生成一個(gè)帶有app-routing.module.ts
路由模塊的項(xiàng)目概行。
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
app.module.ts
模塊中會(huì)導(dǎo)入AppRoutingModule
模塊蠢挡。
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule <<=== add here
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
再生成home
和product
組件。
ng g component home
ng g component product
修改新建組件內(nèi)容
home.component.html
<p>
這里是主頁組件
</p>
product.component.html
<p>
這里是商品信息組件
</p>
添加路由配置
修改app-routin.module.ts
路由配置文件。
import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';
const routes: Routes = [
{path: '', component: HomeComponent},
{path: 'product', component: ProductComponent}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}
修改app.component.html
頁面模版袒哥。
<!--The content below is only a placeholder and can be replaced.-->
<a [routerLink]="['/']">主頁</a>
<a [routerLink]="['/product']">商品詳情</a>
<router-outlet></router-outlet>
routerLink
參數(shù)是數(shù)組類型缩筛,以便傳遞參數(shù)。
運(yùn)行項(xiàng)目
ng serve --open
運(yùn)行項(xiàng)目堡称。
修改app.component.html
給頁面模版添加一個(gè)商品詳情按鈕瞎抛。
<!--The content below is only a placeholder and can be replaced.-->
<a [routerLink]="['/']">主頁</a>
<a [routerLink]="['/product']">商品詳情</a>
<input type="button" value="商品詳情" (click)="toProductDetails()">
<router-outlet></router-outlet>
其中在app.component.ts
實(shí)現(xiàn)toproductDetails()
方法
import {Component} from '@angular/core';
import {Router} from '@angular/router';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'router';
constructor(private router: Router) {
}
toProductDetails() {
this.router.navigate(['product']);
}
}
這里方法中使用Router
的navigate
方法實(shí)現(xiàn)路由跳轉(zhuǎn)。
這里routeLink
是通過前端頁面實(shí)現(xiàn)跳轉(zhuǎn)却紧,而navigate
是通過后臺(tái)組件實(shí)現(xiàn)跳轉(zhuǎn)桐臊。
實(shí)現(xiàn)訪問不存在頁面跳轉(zhuǎn)
創(chuàng)建code404組件,實(shí)現(xiàn)默認(rèn)跳轉(zhuǎn)頁面晓殊。
ng g component code404
code404.component.html
頁面模版內(nèi)容断凶。
<p>
404 Not Found!
</p>
路由配置,修改app-routing.module.ts
巫俺,添加頁面不存時(shí)顯示頁面认烁。
import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';
import {Code404Component} from './code404/code404.component';
const routes: Routes = [
{path: '', component: HomeComponent},
{path: 'product', component: ProductComponent},
{path: '**', component: Code404Component}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}
路由器使用先匹配者優(yōu)先選擇原則,所以通配符路由要放在路由配置的最后面介汹。
路由時(shí)傳遞數(shù)據(jù)
第一種方式
/product?id=1&name=2 => ActivateRoute.queryParams[id]
第二種方式
{path: /product/:id} => /product/1 => ActivateRoute.params[id]
第三種方式
{path: /product, component: ProductComponent, data: [{isProd: true}]} => ActivateRoute.data[0][isProd]
修改app.component.html
頁面模版却嗡。
<!--The content below is only a placeholder and can be replaced.-->
<a [routerLink]="['/']">主頁</a>
<a [routerLink]="['/product']" [queryParams]="{id: 1}">商品詳情</a>
<input type="button" value="商品詳情" (click)="toProductDetails()">
<router-outlet></router-outlet>
點(diǎn)擊頁面商品詳情
鏈接,URL跳轉(zhuǎn)變?yōu)?code>http://localhost:4200/product?id=1嘹承。
下面來看看怎么在商品詳情組件中接受這個(gè)傳遞參數(shù)窗价。
首先在商品詳情組件product.component.ts
中注入ActivatedRoute
組件,然后在其中聲明一個(gè)productId
來接收傳進(jìn)來的id
叹卷,如第一種方式所示撼港,使用queryParams
獲取傳遞值。
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
@Component({
selector: 'app-product',
templateUrl: './product.component.html',
styleUrls: ['./product.component.css']
})
export class ProductComponent implements OnInit {
private productId: number;
constructor(private routeInfo: ActivatedRoute) {
}
ngOnInit() {
this.productId = this.routeInfo.snapshot.queryParams['id'];
}
}
頁面上展示ID值骤竹。
<p>
這里是商品信息組件
</p>
<p>
商品ID是: {{productId}}
</p>
修改app-routing.module.ts
路由配置中的path
屬性使其可以攜帶參數(shù)帝牡。
import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';
import {Code404Component} from './code404/code404.component';
const routes: Routes = [
{path: '', component: HomeComponent},
{path: 'product/:id', component: ProductComponent},
{path: '**', component: Code404Component}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}
然后修改app.component.html
路由鏈接的參數(shù)來傳遞數(shù)據(jù)。
<!--The content below is only a placeholder and can be replaced.-->
<a [routerLink]="['/']">主頁</a>
<a [routerLink]="['/product', 1]">商品詳情</a>
<input type="button" value="商品詳情" (click)="toProductDetails()">
<router-outlet></router-outlet>
點(diǎn)擊頁面商品詳情
鏈接蒙揣,URL跳轉(zhuǎn)變?yōu)?code>http://localhost:4200/product/1
如第二種方式否灾,修改商品詳情組件product.component.ts
,將queryParams
改為params
即可鸣奔。
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
@Component({
selector: 'app-product',
templateUrl: './product.component.html',
styleUrls: ['./product.component.css']
})
export class ProductComponent implements OnInit {
private productId: number;
constructor(private routeInfo: ActivatedRoute) {
}
ngOnInit() {
this.productId = this.routeInfo.snapshot.params['id'];
}
}
點(diǎn)擊商品詳情鏈接頁面上展示ID值為1。
<u>什么是參數(shù)快照惩阶?什么是參數(shù)訂閱挎狸?</u>
參數(shù)快照就是snapshot
,這里如果切換商品詳情頁面断楷,雖然URL會(huì)來回切換锨匆,但是ID的顯示值并不會(huì)改變。所以采用參數(shù)訂閱方式。
參數(shù)訂閱恐锣,subscribe
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute, Params} from '@angular/router';
@Component({
selector: 'app-product',
templateUrl: './product.component.html',
styleUrls: ['./product.component.css']
})
export class ProductComponent implements OnInit {
private productId: number;
constructor(private routeInfo: ActivatedRoute) {
}
ngOnInit() {
// this.productId = this.routeInfo.snapshot.params['id'];
this.routeInfo.params.subscribe((params: Params) => this.productId = params['id']);
}
}
重定向路由
在用戶訪問一個(gè)特定的地址時(shí)茅主,將其重定向到另一個(gè)指定的地址。
www.aaa.com => www.aaa.com/products
www.aaa.com/x => www.aaa.com/y
修改app-routing.module.ts
土榴,添加重定向路由诀姚。
import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';
import {Code404Component} from './code404/code404.component';
const routes: Routes = [
{path: '', redirectTo: '/home', pathMatch: 'full'},
{path: 'home', component: HomeComponent},
{path: 'product/:id', component: ProductComponent},
{path: '**', component: Code404Component}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}
子路由
{path: 'home', component: HomeComponent}
{path: 'home', component: HomeComponent,
children: [
{
path: '', component: XxxComponent
},
{
path: '/yyy', component: YyyComponent
}
]}
新建商品描述組件和商品銷售員組件。
ng g component product-desc
和ng g component seller-info
修改product-desc.component.html
模版頁面內(nèi)容玷禽。
<p>
這是一個(gè)商品描述頁面
</p>
修改seller-info.component.html
模版頁面內(nèi)容赫段,并傳遞sellerId
。
<p>
銷售員ID是:{{sellerId}}
</p>
修改seller-info.component.ts
控制器內(nèi)容矢赁,獲取路由傳遞參數(shù)。
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
@Component({
selector: 'app-seller-info',
templateUrl: './seller-info.component.html',
styleUrls: ['./seller-info.component.css']
})
export class SellerInfoComponent implements OnInit {
private sellerId: number;
constructor(private routeInfo: ActivatedRoute) {
}
ngOnInit() {
this.sellerId = this.routeInfo.snapshot.params['id'];
}
}
修改app-routing.module.ts
,添加商品子路由配置志珍。
import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';
import {Code404Component} from './code404/code404.component';
import {ProductDescComponent} from './product-desc/product-desc.component';
import {SellerInfoComponent} from './seller-info/seller-info.component';
const routes: Routes = [
{path: '', redirectTo: '/home', pathMatch: 'full'},
{path: 'home', component: HomeComponent},
{
path: 'product/:id', component: ProductComponent,
children: [
{path: '', component: ProductDescComponent},
{path: 'seller/:id', component: SellerInfoComponent}
]
},
{path: '**', component: Code404Component}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}
然后修改product.component.html
模版頁面鬼佣,添加路由選項(xiàng)。
<p>
這里是商品信息組件
</p>
<p>
商品ID是: {{productId}}
</p>
<a [routerLink]="['./']">商品描述</a>
<a [routerLink]="['./seller', 99]">銷售員信息</a>
<router-outlet></router-outlet>
這里./
表示當(dāng)前頁面下面的路由選項(xiàng)這里就是http://localhost:4200/product/1/seller/99
额获。
輔助路由
<router-outlet></router-outlet>
<router-outlet name="aux"></router-outlet>
{path: 'xxx', component: XxxComponent, outlet: "aux"}
{path: 'yyy', component: YyyComponent, outlet: "aux"}
<a [routerLink]="['/home', {outlets: {aux: 'xxx'}}]">Xxx</a>
<a [routerLink]="['/product', {outlets: {aux: 'yyy'}}]">Yyy</a>
新建聊天組件
ng g component chat
修改模版頁面內(nèi)容
<textarea placeholder="content" class="chat"></textarea>
修改app-routing.module.ts
够庙,添加輔助路由配置。
import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';
import {Code404Component} from './code404/code404.component';
import {ProductDescComponent} from './product-desc/product-desc.component';
import {SellerInfoComponent} from './seller-info/seller-info.component';
import {ChatComponent} from './chat/chat.component';
const routes: Routes = [
{path: '', redirectTo: '/home', pathMatch: 'full'},
{path: 'chat', component: ChatComponent, outlet: 'aux'},
{path: 'home', component: HomeComponent},
{
path: 'product/:id', component: ProductComponent,
children: [
{path: '', component: ProductDescComponent},
{path: 'seller/:id', component: SellerInfoComponent}
]
},
{path: '**', component: Code404Component}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}
然后修改app.component.html
路由鏈接的參數(shù)來傳遞數(shù)據(jù)咪啡。
<!--The content below is only a placeholder and can be replaced.-->
<a [routerLink]="['/home']">主頁</a>
<a [routerLink]="['/product', 1]">商品詳情</a>
<input type="button" value="商品詳情" (click)="toProductDetails()">
<a [routerLink]="[{outlets: {aux: 'chat'}}]">開始聊天</a>
<a [routerLink]="[{outlets: {aux: null}}]">結(jié)束聊天</a>
<router-outlet></router-outlet>
<router-outlet name="aux"></router-outlet>
如果想同時(shí)指定這時(shí)主路由的跳轉(zhuǎn)首启,還請修改為
<a [routerLink]="[{outlets: {primary: 'home', aux: 'chat'}}]">開始聊天</a>
路由守衛(wèi)
只有當(dāng)用戶已經(jīng)登錄并擁有某些權(quán)限時(shí)才能進(jìn)入某些路由。
一個(gè)由多個(gè)表單組件組成的向?qū)С访缱粤鞒桃闾遥脩糁挥性诋?dāng)前路由的組件中填寫了滿足要求的信息才可以導(dǎo)航到下一個(gè)路由。
當(dāng)用戶未執(zhí)行保存操作而試圖離開當(dāng)前導(dǎo)航時(shí)提醒用戶准夷。
CanActivate
:處理導(dǎo)航到某路由的情況钥飞。
CanDeactivate
:處理從當(dāng)前路由離開的情況。
Resolve
:在路由激活之前獲取路由數(shù)據(jù)衫嵌。
添加自定義路由守衛(wèi)login.guard.ts
import {CanActivate} from '@angular/router';
export class LoginGuard implements CanActivate {
canActivate() {
let loginIn: boolean = Math.random() < 0.5;
if (!loginIn) {
console.log('用戶未登錄');
}
return loginIn;
}
}
修改app-routing.module.ts
读宙,添加路由守衛(wèi)配置。
import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';
import {Code404Component} from './code404/code404.component';
import {ProductDescComponent} from './product-desc/product-desc.component';
import {SellerInfoComponent} from './seller-info/seller-info.component';
import {ChatComponent} from './chat/chat.component';
import {LoginGuard} from './guard/login.guard';
const routes: Routes = [
{path: '', redirectTo: '/home', pathMatch: 'full'},
{path: 'chat', component: ChatComponent, outlet: 'aux'},
{path: 'home', component: HomeComponent},
{
path: 'product/:id', component: ProductComponent,
children: [
{path: '', component: ProductDescComponent},
{path: 'seller/:id', component: SellerInfoComponent}
], canActivate: [LoginGuard]
},
{path: '**', component: Code404Component}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [LoginGuard]
})
export class AppRoutingModule {
}
并且通過在providers
添加LoginGuard
來實(shí)現(xiàn)依賴注入楔绞。LoginGuard
實(shí)現(xiàn)CanActivate
方法结闸。
CanDeactivate
同理。
添加product.resolve.ts
酒朵,如果productId
值為1則創(chuàng)建新對象傳遞進(jìn)商品詳情頁面桦锄,否則跳轉(zhuǎn)到主頁。
import {ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot} from '@angular/router';
import {Observable} from 'rxjs';
import {Product} from '../product/product.component';
import {Injectable} from '@angular/core';
@Injectable()
export class ProductResolve implements Resolve<Product> {
constructor(private router: Router) {
}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Product> | Promise<Product> | Product {
let productId: number = route.params['id'];
if (productId == 1) {
return new Product(1, 'Iphone7');
} else {
this.router.navigate(['/home']);
}
}
}
修改app-routing.module.ts
蔫耽,添加reslove
路由守衛(wèi)配置结耀。
import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';
import {Code404Component} from './code404/code404.component';
import {ProductDescComponent} from './product-desc/product-desc.component';
import {SellerInfoComponent} from './seller-info/seller-info.component';
import {ChatComponent} from './chat/chat.component';
import {LoginGuard} from './guard/login.guard';
import {ProductResolve} from './guard/product.resolve';
const routes: Routes = [
{path: '', redirectTo: '/home', pathMatch: 'full'},
{path: 'chat', component: ChatComponent, outlet: 'aux'},
{path: 'home', component: HomeComponent},
{
path: 'product/:id', component: ProductComponent,
children: [
{path: '', component: ProductDescComponent},
{path: 'seller/:id', component: SellerInfoComponent}
], resolve: {
product: ProductResolve
}
},
{path: '**', component: Code404Component}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [ProductResolve]
})
export class AppRoutingModule {
}
resolve
中參數(shù)是一個(gè)對象,product是想傳遞進(jìn)去參數(shù)的名字,然后用ProductResolve
來生成图甜。
在商品信息組件中在聲明productName
product.component.ts
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute, Params} from '@angular/router';
@Component({
selector: 'app-product',
templateUrl: './product.component.html',
styleUrls: ['./product.component.css']
})
export class ProductComponent implements OnInit {
private productId: number;
private productName: string;
constructor(private routeInfo: ActivatedRoute) {
}
ngOnInit() {
// this.productId = this.routeInfo.snapshot.params['id'];
this.routeInfo.params.subscribe((params: Params) => this.productId = params['id']);
this.routeInfo.data.subscribe((data: { product: Product }) => {
this.productId = data.product.id;
this.productName = data.product.name;
});
}
}
export class Product {
constructor(public id: number, public name: string) {
}
}
將傳遞進(jìn)來product
對象的id
和name
賦予我本地的productId
和productName
屬性碍粥。
修改模版頁面product.component.html
<div class="product">
<p>
這里是商品信息組件
</p>
<p>
商品ID是: {{productId}}
</p>
<p>
商品名稱是: {{productName}}
</p>
<a [routerLink]="['./']">商品描述</a>
<a [routerLink]="['./seller', 99]">銷售員信息</a>
<router-outlet></router-outlet>
</div>