ng2 路由
https://angular.cn/guide/router
激活路由参数
添加路由动画
懒加载路由
创建模块来放置模块相关的组件,比如购买就放置购买相关的组件,和路由 创建模块路由注意 app.module.ts 中import导入的顺序, AppRoutingModule 是最后一个
考虑让每个特性模块都有自己的路由配置文件
在 AppRoutingModule 中,使用静态的 RouterModule.forRoot方法来注册路由和全应用级服务提供商
在特性模块中,你要改用forChild静态方法
ng generate module app-routing --flat --module=app
$ ng g module --help
--module=app // 把它注册到 App.module 的 imports 数组中
--flat // 如果为true,则在当前项目根目录的顶级创建新文件
--routing // 如果为true,则创建路由模块。
--routing-scope // 新路由模块的范围。
配置 app-routing.module.ts
const routes: Routes = [
{
path: "",
component: DashboardComponent,
children: [
{ path: "home", component: HomeComponent },
{
path: "about",
component: AboutComponent,
},
{ path: "", redirectTo: "home", pathMatch: "full" },
],
},
// 注册404页面
{path: 'not-found', component: NotFoundComponent },
// 当没有匹配到任何页面,跳转到404
{path: '**', redirectTo: '/not-found', pathMatch: 'full'},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
app/app.component.html
<router-outlet></router-outlet>
app/pages/dashboard/dashboard.component.html
<nav mat-tab-nav-bar backgroundColor="primary" color='accent'>
<a
mat-tab-link
*ngFor="let link of navLinks"
[routerLink]="link.path"
routerLinkActive
#rla="routerLinkActive"
[active]="rla.isActive"
>
{{ link.label }}
</a>
</nav>
<router-outlet></router-outlet>
// ts
navLinks = [
{
path: "/home",
label: "home",
},
{
path: "/about",
label: "about",
},
{
path: "/welcome",
label: "welcome",
},
];
app.module.ts 中注册 router(一般cli已经帮你注册好了)
import { AppRoutingModule } from './app-routing.module'; //
@NgModule({
imports: [ AppRoutingModule ]
})
export class AppModule { }
动态路由
const routers: Routes = [
{ path: 'login/:id', component: LoginComponent } // 加上:id 就是动态路由了
];
home.component.html
<a routerLink="/login/a">to login page</a>
<a [routerLink]="['/login', 'a']">to login page</a>
从路由参数中提取 id
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Location } from '@angular/common';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
constructor(
private route: ActivatedRoute,
private localtion: Location
) { }
ngOnInit() {
console.log( this.route.snapshot.paramMap.get('id') ); // 获取id参数 => a
}
}
事件激活路由 docs
import { Router } from '@angular/router';
constructor( private router: Router ) {}
toTest() {
this.router.navigate(['/test', {id: Math.random(), name: 'test.'}]); // route.snapshot.paramMap.get('id') 获取参数
}
// 触发动态路由
toTest() {
this.router.navigate(['/test', 233]);
}
路由守卫 文档
守卫返回一个值,以控制路由器的行为
- true,导航过程会继续
- false,导航过程就会终止,且用户留在原地
- UrlTree,则取消当前的导航,并且开始导航到返回的这个 UrlTree
守卫可以用同步的方式返回一个布尔值。但在很多情况下都是异步操作。因此可以返回 Observable
路由器可以支持多种守卫接口:
- 用CanActivate来处理导航到某路由的情况。假如绑定到"home"守卫返回false的情况,直接访问home会被拦截,直接访问home/child也会被拦截 canActivate只会在父组件尚未创建时执行
- 用CanActivateChild来处理导航到某子路由的情况。在子路由中导航时会被执行
- 用CanDeactivate来处理从当前路由离开的情况.
- 用Resolve在路由激活之前获取路由数据。
- 用CanLoad来处理异步导航到某特性模块的情况。
canDeactivate
修改了数据情况,询问用户是否确认离开
import { Injectable } from "@angular/core";
import { ActivatedRouteSnapshot, RouterStateSnapshot } from "@angular/router";
import { Observable } from "rxjs";
import { CanDeactivate } from "@angular/router";
import { HomeComponent } from "./home/home.component";
@Injectable({
providedIn: "root",
})
export class CanDeactivateGuard implements CanDeactivate<HomeComponent> {
canDeactivate(
component: HomeComponent, // 获取组件实例
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot,
): Observable<boolean> | Promise<boolean> | boolean {
if (component.username === "ajanuw") {
return true;
}
return window.confirm("您确定放弃修改,并退出页面吗?");
}
}
canActivate
权限拦截
import { Injectable } from "@angular/core";
import {
CanActivate,
ActivatedRouteSnapshot,
RouterStateSnapshot,
Router,
} from "@angular/router";
import { Observable } from "rxjs";
@Injectable({
providedIn: "root",
})
export class AuthGuard implements CanActivate {
constructor(private readonly router: Router) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot,
): Observable<boolean> | Promise<boolean> | boolean {
let isLogin = false; // 硬編碼
// 验证登陆后通过,否则从定向
if (isLogin) return true;
this.router.navigate(["/"]);
return false;
}
}
发送对象
// to
this.router.navigate(['/screen2'], {
state: {
a: 'hello',
b: 'NG',
},
});
// newPage
export class Screen2Component implements OnInit {
constructor(
private router: Router,
) {
const navigation = this.router.getCurrentNavigation();
const state = navigation.extras.state as {
a: string;
b: string;
};
console.log(state);
}
ngOnInit() {}
}
懒加载路由(模块)
通常类似admin这样的模块并不是谁都能访问的.
快速创建admin模块
λ ng g module admin --module app --route admin
上面的命令在src/admin下创建后,会自动在AppRoutingModule里面注册,如:
import { NgModule, Injectable } from "@angular/core";
import { Routes, RouterModule, Resolve } from "@angular/router";
import { HomeComponent } from "./home/home.component";
import { AboutComponent } from "./about/about.component";
@Injectable({
providedIn: "root"
})
export class ThrottleService implements Resolve<any> {
resolve() {
return new Promise(resolve => setTimeout(resolve, 2000));
}
}
const routes: Routes = [
{
path: "",
component: HomeComponent,
pathMatch: "full"
},
{
path: "about",
component: AboutComponent
},
{
path: "admin",
loadChildren: () => import("./admin/admin.module").then(m => m.AdminModule),
resolve: {
// 引入了延迟,以便您可以看到微调器在起作用
// resolve 通常是为了在导航到路由页面前,提前获取数据
ThrottleService: ThrottleService
}
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
<router-outlet>
<span class="loader" *ngIf="loading">loading...</span>
</router-outlet>
import {
Router,
RouterEvent,
NavigationStart,
NavigationEnd
} from "@angular/router";
export class DashboardComponent implements OnInit {
loading = false;
constructor(private readonly router: Router) {
this.router.events.subscribe((event: RouterEvent): void => {
if (event instanceof NavigationStart) {
this.loading = true;
} else if (event instanceof NavigationEnd) {
this.loading = false;
}
});
}
}
预加载延迟路由
延迟路由适合初始页面加载,但它会减慢导航速度
- 使用PreloadAllModules, 它会预先加载所有延迟加载的路由
RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
- 自定义预加载策略, 只预加载那些 data.preload 标志为 true 的路由
import { NgModule, Injectable } from "@angular/core";
import {
Routes,
RouterModule,
Resolve,
PreloadAllModules,
PreloadingStrategy,
Route
} from "@angular/router";
import { HomeComponent } from "./home/home.component";
import { AboutComponent } from "./about/about.component";
import { Observable, of } from "rxjs";
@Injectable({
providedIn: "root"
})
export class SelectivePreloadingStrategyService implements PreloadingStrategy {
preloadedModules: string[] = [];
preload(route: Route, load: () => Observable<any>): Observable<any> {
if (route.data && route.data["preload"]) {
this.preloadedModules.push(route.path);
return load();
} else {
return of(null);
}
}
}
const routes: Routes = [
...
{
path: "admin",
loadChildren: () => import("./admin/admin.module").then(m => m.AdminModule),
// 将preload改为true,将自动加载
data: { preload: false }
}
];
@NgModule({
imports: [
RouterModule.forRoot(routes, {
// 使用实现了preload的服务
preloadingStrategy: SelectivePreloadingStrategyService
})
],
providers: [SelectivePreloadingStrategyService],
exports: [RouterModule]
})
export class AppRoutingModule {}
- 使用 ngx-quicklink 如果延迟路由的连接出现在页面上,就开始预加载
npm install --save ngx-quicklink
可以将 QuicklinkModule 导入 SharedModule 中
import {QuicklinkStrategy, QuicklinkModule} from 'ngx-quicklink';
…
@NgModule({
…
imports: [
…
QuicklinkModule,
RouterModule.forRoot([…], {
preloadingStrategy: QuicklinkStrategy
})
],
…
})
export class AppModule {}
如果要忽略掉ngx-quicklink
{
path: 'contact',
loadChildren: import(() => './contact/contact.module').then(m => m.ContactModule),
data: {
// 设置为false
preload: false
}
}
- 使用guess.js 来预测用户会进入那些页面,在进行预加载 guess&angular