SPA
single page web application,單頁Web應用
視圖狀態列表集合
不重新加載頁面
路由知識
1.創建項目
–>ng new router --routing
2.生成組件
–>ng g component home
–>ng g component product
2.1Routes路由配置
app-routing.module.ts
import {ProductComponent} from './product/product.component';
const routes: Routes = [
/*根路由*/
{path: '', component: HomeComponent},
{path: 'product', component: ProductComponent}
];
2.2 RouterOutlet路由插座
app.component.html
<router-outlet></router-outlet>
2.3 RouterLink路由導航
app.component.html
<a [routerLink]="['/']">主頁</a>
<a [routerLink]="['/product']">商品詳情</a>
注:參數是數組,路由傳參
運行看效果:–> npm run start
2.4 Router路由導航
app.component.html
<!--(click):事件綁定-->
<input type="button" value="商品詳情" (click)="toProductDetails()">
app.component.ts
import {Router} from '@angular/router';
export class AppComponent {
title = 'router';
/*獲得router對象*/
constructor(private router: Router) {
}
toProductDetails() {
/*通過router對象navigate方法導航*/
this.router.navigate(['/product']);
}
}
問題
問題:url輸入路徑不存在,報錯
解決:
1.–> ng g component code404
2.app-routing.module.ts
import {Code404Component} from './code404/code404.component';
const routes: Routes = [
/*根路由*/
{path: '', component: HomeComponent},
{path: 'product', component: ProductComponent},
{path: '**', component: Code404Component}
];
注:通配符路由最後配置
2.5 ActivatedRoute
2.5.1在路由時傳遞數據:
1.在查詢參數中傳遞數據
/product?id=1&name=2
=> ActivatedRoute.queryParams[id]
app.component.html
<a [routerLink]="['/product']" [queryParams]="{id: 1}">商品詳情</a>
product.component.ts
import {ActivatedRoute} from '@angular/router';
export class ProductComponent implements OnInit {
private productId: number;
constructor(private routeInfo: ActivatedRoute) { }
ngOnInit() {
this.productId = this.routeInfo.snapshot.queryParams['id'];
}
}
product.component.html
<p>
商品ID是{{productId}}
</p>
瀏覽器點擊顯示:http://localhost:4200/product?id=1
2.在路由路徑中傳遞數據
{path: ‘product/:id’ }
=> /product/1
=> ActivatedRoute.params[id]
app.component.html
<a [routerLink]="['/product', 1]">商品詳情</a>
product.component.ts
import {ActivatedRoute} from '@angular/router';
export class ProductComponent implements OnInit {
private productId: number;
constructor(private routeInfo: ActivatedRoute) { }
ngOnInit() {
//this.productId = this.routeInfo.snapshot.queryParams['id'];
this.productId = this.routeInfo.snapshot.params['id'];
}
}
瀏覽器點擊顯示:http://localhost:4200/product/1
3.在路由配置中傳遞數據
{path: product,component: ProductComponent , data [{isProd:true}]}
=> ActivatedRoute.data[0][isProd]
問題
修改app.component.ts
import {Router} from '@angular/router';
export class AppComponent {
...
toProductDetails() {
this.router.navigate(['/product', 2]); }
}
問題:頁面點擊商品詳情鏈接和按鈕,url改變,html展示不變
原因:商品詳情組件不會再次創建,ngOnInit()方法不會再次執行
解決:修改product.component.ts
參數快照:
this.productId = this.routeInfo.snapshot.params['id'];
參數訂閱:
this.routeInfo.params.subscribe((params: Params) => this.productId = params['id']);
3.重定向路由
修改app-routing.module.ts
const routes: Routes = [
/*重定向*/
{path: '', redirectTo: '/home', pathMatch: 'full'},
{path: 'home', component: HomeComponent},
/*{path: 'product', component: ProductComponent},*/
{path: 'product/:id', component: ProductComponent},
{path: '**', component: Code404Component}
];
4.子路由
4.1添加商品詳情子組件
商品描述:–>類似home組件
-> ng g component productDesc
銷售員信息:–>類似product組件
-> ng g component sellerInfo
4.2商品詳情子路由配置
product.component.html
<a [routerLink]="['./']">商品描述</a>
<a [routerLink]="['./seller', 99]">銷售員信息</a>
<router-outlet></router-outlet>
app-routing.module.ts
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}
];
5.輔助路由
1.路由插座
輔助插座 ,
app.component.html
<router-outlet name="aux"></router-outlet>
2.生成聊天組件
-> ng g component chat
chat.component.html
<textarea placeholder='請輸入聊天內容'></textarea>
3.路由配置
app-routing.module.ts
const routes: Routes = [
/*根路由*/
{path: '', redirectTo: '/home', pathMatch: 'full'},
/*添加chat路由配置*/
{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}
];
4.路由導航
app.component.html
<a [routerLink]="[{outlets: {aux: 'chat'}}]">開始聊天</a>
<a [routerLink]="[{outlets: {aux: null}}]">結束聊天</a>
追加:主路由沒有name,使用primary指定
<a [routerLink]="[{outlets: {primary: ‘home’, aux: ‘chat’}}]">開始聊天
6.路由守衛
路由守衛:
- CanActivate : 處理導航到某路由的情況
- CanDeactivate: 處理從當前路由離開的情況
- Resolve:在路由激活之前獲取路由數據
使用場景:
1.用戶登錄並擁有某些權限–》進入某些路由
app下新建目錄:guard
guid下新建文件:login.guard.ts
login.guard.ts
import {CanActivate} from '@angular/router';
export class LoginGuard implements CanActivate{
canActivate() {
let loggedIn: boolean = Math.random()<0.5;
if(!loggedIn) {
console.log("用戶未登錄");
}
return loggedIn;
}
}
app-routing.module.ts
const routes: Routes = [
/*根路由*/
{path: '', redirectTo: '/home', pathMatch: 'full'},
/*添加chat路由配置*/
{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],
/*聲明LoginGuard*/
providers: [LoginGuard]
})
注:
只是指定路由守衛的類型,未實例化LoginGuard
Angular採用依賴注入方式實例化LoginGuard
2.用戶未執行保存操作而試圖離開當前導航時提醒用戶
guid下新建文件:unsaved.guard.ts
unsaved.guard.ts
import {CanDeactivate} from '@angular/router';
import {ProductComponenent} from '../product/product.component';
export class UnsavedGuard implements CanDeactivate<ProductComponenent>{
canDeactivate(componenent: ProductComponenent) {
return window.confirm("未保存,離開?");
}
}
app-routing.module.ts
const routes: Routes = [
/*根路由*/
{path: '', redirectTo: '/home', pathMatch: 'full'},
/*添加chat路由配置*/
{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],
canDeactivate: [UnsavedGuard] },
{path: '**', component: Code404Component}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
/*聲明UnsavedGuard*/
providers: [LoginGuard, UnsavedGuard]
})
3.有多個表單組件組成的嚮導:如
註冊流程–》用戶只有在當前路由的組件中填寫滿足要求的信息纔可以導航到下一個路由
7.resolve守衛
解決問題:
before:項目使用http獲取數據有延時,模板數據加載問題,用戶體驗差
after:在進入組件之前,把組件所需數據全加載好,如果出錯–》彈出,不進入目標路由
guid下新建文件:product.resolve.ts
product.resolve.ts
import {Resolve} from '@angular/router';
import {Product} from '../product/product.component';
import {Injectable} from '@angular/core';
/*<Product>: resolve解析出來數據類型*/
@Injectable
/*裝飾器,constructor中的router才能被注入進來
*component不需要,已經繼承裝飾器
*/
export class ProductResolve implements Resolve<Product>{
constructor(private router: RouterStateSnapshot) {}
resolve(route: ActivatedRouteSnapshot, state: RouteStateSnapshot: Observable<Product>|Promise<Product>) {
let productId : number;
productId = router.params['id'];
if(productId == 1) {
return new Product(1, 'iphone7');
}else{
this.router.navigate(['/home']);
return undefined;
}
}
}
product.component.ts
export class ProductComponent implements OnInit {
private productId: number;
private productName: string;
...
ngOnInit() {
this...
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) {}
}
app-routing.module.ts
const routes: Routes = [
/*根路由*/
{path: '', redirectTo: '/home', pathMatch: 'full'},
/*添加chat路由配置*/
{path: 'chat',component: ChatComponent, outlet: 'aux'},
{path: 'home', component: HomeComponent},
/*添加resolve守衛配置*/
{path: 'product/:id', component: ProductComponent, children: [
/*子路由*/
{path: '', component: ProductDescComponent},
{path: 'seller/:id', component: SellerInfoComponent}
], resolve: {
product: ProductResolved
}
},
{path: '**', component: Code404Component}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
/*聲明ProductResolved*/
providers: [LoginGuard, UnsavedGuard, ProductResolved]
})
product.component.html
<p>商品名稱是: {{productName}}</p>