1.基础知识
- 大多数带路由的应用都要在index.html的 标签下先添加一个 元素,来告诉路由器该如何合成导航用的 URL。
<base href="/">
//浏览器访问为:
http://localhost:4200/#/login
- 从@angular/router包中引入路由。
import { RouterModule, Routes } from '@angular/router';
- 路由器需要先配置才会有路由信息。
//我们可以在app.module.ts中进行配置
//路由数组 appRoutes 描述如何进行导航
//path 不能以斜杠(/)开头
//路由器使用先匹配者优先的策略来匹配路由,所以,具体路由应该放在通用路由的前面
const appRoutes: Routes = [
{
path: 'login',
component: LoginPage,
},
{
path: 'reg',
component: RegPage,
},
{
path: 'resetPwd',
component: ResetPwdPage,
},
{ path: '', redirectTo: '/login', pathMatch: 'full' },
{ path: '**', component: NotFoundPage }
];
@NgModule({
declarations:[
LoginPage,
RegPage,
ResetPwdPage,
NotFoundPage,
],
imports: [
BrowserModule,
RouterModule.forRoot(
appRoutes,
{
//把每个导航生命周期中的事件输出到浏览器的控制台
enableTracing: false// <-- debugging purposes only
}
)
],
exports: [
RouterModule
],
providers: [
],
bootstrap: [AppComponent],
})
export class AppModule{ }
- 路由出口。
路由插座:显示路由器生成的视图。在展示父路由的位置中的某个地方展示子路由对应的地方。
<router-outlet></router-outlet>
路由链接。
<a [routerLink]="['/login']" >Login Page</a>
这是我的常用方式,其他写法可参考:https://www.cnblogs.com/jiagoushi/p/6108039.html
路由传参。
在路由中传参有3种方法:
1.routerLink
//单一参数:
page:<a routerLink="/storeProdList/statu"></a>
router:
{ path: 'storeProdList/:statu',
component: StoreProdListPage
}
//多个参数:queryParams携带多个参数,这个参数的格式可以是自行组织的object
routerLink=["/exampledetail",{queryParams:object}]`
//也可以分开多个参数写成
routerLink=["/exampledetail",{queryParams:'id':'1','name':'yxman'}]
2.router.navigate
单一参数:this.router.navigate(['/exampledetail',id]),多用在调用方法里
多个参数:this.router.navigate(['/exampledetail'],{queryParams:{'name':'helen'}})
3.router.navigateByUrl:
单一参数:this.router.navigateByUrl('/exampledetail/id');
多个参数:this.router.navigateByUrl('/exampledetail',{queryParams:{'name':'yxman'}});
接收参数方式如下:
方式1:
import { ActivateRoute } from '@angular/router';
public data: any;
constructor( public route: ActivateRoute ) { };
ngOnInit(){
this.data = this.route.snapshot.params['id'];
};
方式2:
import { ActivateRoute } from '@angular/router';
public data: any;
constructor( public activeRoute:ActivateRoute ) { };
ngOnInit(){
this.activeRoute.queryParams.subscribe(params => {
this.data = params['name'];
});
};
2.路由模块:统一管理路由
在 /app 目录下创建一个名叫 app-routing.module.ts 的文件,以包含这个路由模块。
修改 app.module.ts 文件,把 imports 数组中的 RouterModule.forRoot 替换为 AppRoutingModule。
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
......
import {NotFoundPage} from "./notFoundPage";
const appRoutes: Routes = [
{
path: 'login',
component: LoginPage,
},
{
path: 'reg',
component: RegPage,
},
{
path: 'resetPwd',
component: ResetPwdPage,
},
{ path: '', redirectTo: '/login', pathMatch: 'full' },
{ path: '**', component: NotFoundPage }
];
@NgModule({
declarations:[
LoginPage,
RegPage,
ResetPwdPage,
NotFoundPage,
],
imports: [
BrowserModule,
RouterModule.forRoot(
appRoutes,
{
//把每个导航生命周期中的事件输出到浏览器的控制台
enableTracing: false// <-- debugging purposes only
}
)
],
exports: [
RouterModule
],
providers: [
],
bootstrap: [AppComponent],
})
export class AppRoutingModule{ }
3.路由守卫
3.1. 概述
路由守卫,应用在这个路由不是对所有导航都有效的,是有一些前置条件的,比如可能用户得先登录(认证)或者在显示目标组件前,你可能得先获取某些数据等等,只有当这些前置条件满足的时候,才能被导航到该页面。
你可以往路由配置中添加守卫,守卫返回一个boolean值,以控制路由器的行为:如果它返回
true,导航过程会继续,如果它返回 false,导航过程会终止,且用户会留在原页面。当然这时候也可以被导航到其他页面。也可以返回一个Observable或Promise,并且路由器会等待这个可观察对象被解析为true或false。
3.2 路由器可以支持多种守卫接口:
- 用CanActivate来处理导航到某路由的情况。
- 用CanActivateChild来处理导航到某子路由的情况。
- 用CanDeactivate来处理从当前路由离开的情况.
- 用Resolve在路由激活之前获取路由数据。
用CanLoad来处理异步导航到某特性模块的情况。
CanActivate:要求认证
CanActivateChild:保护子路由
这里只列出实现方式,具体的守卫规则可按需求实现。
import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
@Injectable()
export class AuthGuard implements CanActivate,canActivateChild {
constructor(private authService:AuthService){}
canActivate() {
console.log('AuthGuard#canActivate called');
return true;
}
canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
console.log('AuthGuard#canActivateChild called');
//return this.canActivate(route, state);
return true;
}
}
Resolve: 预先获取组件数据
import {Injectable} from "@angular/core";
import {Resolve, ActivatedRouteSnapshot, RouterStateSnapshot} from "@angular/router";
import {AuthData} from "./AuthData";
import {Observable} from "rxjs";
import {AuthService} from "./AuthService";
@Injectable()
export class MainResolve implements Resolve<AuthData>{
constructor(private authService:AuthService){}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<AuthData>|Promise<AuthData>|AuthData {
return this.authService.getAuthData();//导航前预先加载路由信息
}
}
CanDeactivate:处理未保存的更改
import {CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot} from "@angular/router";
import {AddUserComp} from "./user/addUser";
import {Observable} from "rxjs";
import {Injectable} from "@angular/core";
import {AppUtils} from "../../comModule/AppUtils";
@Injectable()
export class UnSaveGuard implements CanDeactivate<AddUserComp>{
canDeactivate(component: AddUserComp, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState?: RouterStateSnapshot): Observable<boolean>|Promise<boolean>|boolean {
//当用户要离开当前页面,提示用户是否保存,此处实现可自行补充
if(nextState.url.indexOf("/user/addUser/") > -1){
return false;
}
......
}
CanLoad - 保护特性模块的加载
懒加载:使用loadChildren属性,设置一个模块的地址, 该地址是 UserModule的文件路径(相对于 app 目录的),加上一个 # 分隔符,再加上导出模块的类名 UserModule。
当路由器导航到这个路由时,它会用 loadChildren 字符串来动态加载 UserModule,然后把 UserModule添加到当前的路由配置中。
{
path:"user",
loadChildren:'myApp/views/user/user.module#UserModule',
canload:[AnthGuard]
},
预加载:在每次成功的导航后,路由器会在自己的配置中查找尚未加载并且可以预加载的模块。 是否加载某个模块,以及要加载哪些模块,取决于预加载策略。
Router 内置了两种预加载策略:
- 完全不预加载,这是默认值。惰性加载的特性区仍然会按需加载。
- 预加载所有惰性加载的特性区。
要为所有惰性加载模块启用预加载功能,请从 Angular 的路由模块中导入 PreloadAllModules。值得注意的是CanLoad 会阻塞预加载,即 CanLoad 守卫的优先级高于预加载策略。所以上述UserModule仍是按需加载。当然我们也可以自定义预加载策略。
RouterModule.forRoot(
appRoutes,
{
enableTracing: true, // <-- debugging purposes only
preloadingStrategy: PreloadAllModules
}
)
3.3 一个简单的路由管理模块
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import {MainPage} from "./main/main.page";
import {MainGuard} from "../comModule/guard/MainGuard";
import {MainResolve} from "../comModule/guard/MainResolve";
const mRoutes: Routes = [
{
path: "main",
CanActivate:[AnthGuard],
canActivateChild:[AnthGuard],
resolve:{todos:MainResolve},
component: MainPage,
children:[
{path:"user",loadChildren:'myApp/views/user/user.module#UserModule'},
{path:"product",loadChildren:'myApp/views/product/product.module#ProductModule'},
{path:"good",loadChildren:'myApp/views/good/good.module#GoodModule'},
]
}
];
@NgModule({
imports: [
RouterModule.forChild(mRoutes)
],
exports: [
RouterModule
],
providers: [
]
})
export class MainRoutingModule { }