12 Route
12.1 Overview
在 Angular 中,路由是以模块为单位的,每个模块都可以有自己的路由。
12.2 快速上手
- 创建页面组件、Layout 组件以及 Navigation 组件,供路由使用
- 创建首页页面组件
ng g c pages/home
- 创建关于我们页面组件
ng g c pages/about
- 创建布局组件
ng g c pages/layout
-
创建导航组件
ng g c pages/navigation
-
创建路由规则
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [
{
path: "home",
component: HomeComponent
},
{
path: "about",
component: AboutComponent
}
];
- 引入路由模块并启动
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
- 添加路由插座
- 在导航组件中定义链接
src/app/app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LifecycleOnDestoryComponent } from './components/lifecycle/lifecycle-on-destory/lifecycle-on-destory.component';
import { LifecycleOnInitComponent } from './components/lifecycle/lifecycle-on-init/lifecycle-on-init.component';
import { HomeComponent } from './components/route/home/home.component';
import { AboutComponent } from './components/route/about/about.component';
// const routes: Routes = [
// //--- test for lifecycle-destroy--
// {
// path: '', // 根路径
// component: LifecycleOnDestoryComponent, // 显示 HomeComponent
// pathMatch: 'full'
// },
// {
// path: 'LifecycleOnInitComponent', // 显示 AboutComponent
// component: LifecycleOnInitComponent
// }
// //--- test for lifecycle-destroy--
// ];
// route
const routes: Routes = [
{
path: 'home', // 根路径
component: HomeComponent,
},
{
path: 'about', // 显示 AboutComponent
component: AboutComponent
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
src/app/app.component.html
:
src/app/components/route/navigation/navigation.component.html
:
<p>navigation works!</p>
<div>
<a routerLink="/home">home</a>
<br>
<a routerLink="/about">about</a>
</div>
src/app/components/route/route-layout/route-layout.component.html
:
src/app/components/route/home/home.component.html
:
src/app/components/route/about/about.component.html
:
src/app/app-routing.module.ts
:
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LifecycleOnDestoryComponent } from './components/lifecycle/lifecycle-on-destory/lifecycle-on-destory.component';
import { LifecycleOnInitComponent } from './components/lifecycle/lifecycle-on-init/lifecycle-on-init.component';
import { HomeComponent } from './components/route/home/home.component';
import { AboutComponent } from './components/route/about/about.component';
// const routes: Routes = [
// //--- test for lifecycle-destroy--
// {
// path: '', // 根路径
// component: LifecycleOnDestoryComponent, // 显示 HomeComponent
// pathMatch: 'full'
// },
// {
// path: 'LifecycleOnInitComponent', // 显示 AboutComponent
// component: LifecycleOnInitComponent
// }
// //--- test for lifecycle-destroy--
// ];
// route
const routes: Routes = [
{
path: 'home', // 根路径
component: HomeComponent,
},
{
path: 'about', // 显示 AboutComponent
component: AboutComponent
}
];
@NgModule({
imports: [RouterModule.forRoot(routes, { useHash: true })],
exports: [RouterModule]
})
export class AppRoutingModule { }
12.3 匹配规则
12.3.1 重定向
const routes: Routes = [
{
path: 'home', // 根路径
component: HomeComponent,
},
{
path: 'about', // 显示 AboutComponent
component: AboutComponent
},
{
path: '',
// 重定向
redirectTo: 'home',
// 完全匹配
pathMatch: 'full'
// full是完全匹配,prefix是前缀匹配, 默认是prefix
}
];
12.3.2 404 页面
const routes: Routes = [
{
path: 'home', // 根路径
component: HomeComponent,
},
{
path: 'about', // 显示 AboutComponent
component: AboutComponent
},
{
path: '**',
component: NotFoundComponent
},
{
path: '',
// 重定向
redirectTo: 'home',
// 完全匹配
pathMatch: 'full'
// full是完全匹配,prefix是前缀匹配, 默认是prefix
}
];
12.4 Passing Parameters in Routing
12.4.1 查询参数
src/app/components/route/navigation/navigation.component.html
:
<p>navigation works!</p>
<div>
<a routerLink="/home">home</a>
<br>
<a routerLink="/about" [queryParams]="{ name: 'sam' }">about</a>
</div>
src/app/components/route/about/about.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-about',
templateUrl: './about.component.html',
styleUrls: ['./about.component.css']
})
export class AboutComponent implements OnInit {
constructor(private route: ActivatedRoute) { }
ngOnInit() {
this.route.queryParamMap.subscribe(query => {
console.log(query.get('name'));
})
}
}
12.4.2 动态参数
src/app/app-routing.module.ts
:
const routes: Routes = [
{
path: 'home', // 根路径
component: HomeComponent,
},
{
path: 'about/:name', // 显示 AboutComponent
component: AboutComponent
},
{
path: '**',
component: NotFoundComponent
},
{
path: '',
// 重定向
redirectTo: 'home',
// 完全匹配
pathMatch: 'full'
// full是完全匹配,prefix是前缀匹配, 默认是prefix
}
];
@NgModule({
imports: [RouterModule.forRoot(routes, { useHash: true })],
exports: [RouterModule]
})
export class AppRoutingModule { }
src/app/components/route/navigation/navigation.component.html
:
<p>navigation works!</p>
<div>
<a routerLink="/home">home</a>
<br>
<!-- <a routerLink="/about" [queryParams]="{ name: 'sam' }">about</a> -->
<a [routerLink]="['/about','joe']">about</a>
</div>
src/app/components/route/about/about.component.ts
:
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-about',
templateUrl: './about.component.html',
styleUrls: ['./about.component.css']
})
export class AboutComponent implements OnInit {
constructor(private route: ActivatedRoute) { }
ngOnInit() {
// this.route.queryParamMap.subscribe(query => {
// console.log(query.get('name'));
// })
this.route.paramMap.subscribe(query => {
console.log(query.get('name'));
})
}
}
12.5 路由嵌套
路由嵌套指的是如何定义子级路由。
src/app/app-routing.module.ts
:
const routes: Routes = [
{
path: 'home', // 根路径
component: HomeComponent,
},
{
path: 'about/:name', // 显示 AboutComponent
component: AboutComponent
},
{
path: '',
// 重定向
redirectTo: 'home',
// 完全匹配
pathMatch: 'full'
// full是完全匹配,prefix是前缀匹配, 默认是prefix
},
{
path: 'news',
component: NewsComponent,
children: [
{
path: "company",
component: CompanyComponent
},
{
path: "industry",
component: IndustryComponent
}
]
},
{
path: '**',
component: NotFoundComponent
},
// order is important
];
src/app/components/route/news/news.component.html
:
<app-route-layout>
<p>news works!</p>
<div>
<a routerLink="/news/company">Company News</a>
<br>
<a routerLink="/news/industry">Industry News</a>
</div>
<router-outlet></router-outlet>
</app-route-layout>
12.6 命名插座
进入到news, 同时显示company, industry news而不是跳转显示.
将子级路由组件显示到不同的路由插座中.
src/app/app-routing.module.ts
:
// route
const routes: Routes = [
{
path: 'home', // 根路径
component: HomeComponent,
},
{
path: 'about/:name', // 显示 AboutComponent
component: AboutComponent
},
{
path: '',
// 重定向
redirectTo: 'home',
// 完全匹配
pathMatch: 'full'
// full是完全匹配,prefix是前缀匹配, 默认是prefix
},
{
path: 'news',
component: NewsComponent,
children: [
{
path: "company",
component: CompanyComponent,
outlet: "left"
},
{
path: "industry",
component: IndustryComponent,
outlet: "right"
}
]
},
{
path: '**',
component: NotFoundComponent
},
// order is important
];
src/app/components/route/news/news.component.html
:
<app-route-layout>
<p>news works!</p>
<div>
<router-outlet name="left"></router-outlet>
</div>
<div>
<router-outlet name="right"></router-outlet>
</div>
</app-route-layout>
src/app/components/route/navigation/navigation.component.html
:
<p>navigation works!</p>
<div>
<a routerLink="/home">home</a>
<br>
<!-- <a routerLink="/about" [queryParams]="{ name: 'sam' }">about</a> -->
<a [routerLink]="['/about','joe']">about</a>
<br>
<!-- <a routerLink="/news">News</a> -->
<a [routerLink]="['/news', {outlets: {
left: ['company'],
right: ['industry']
} }]">News</a>
</div>
12.7 导航路由
src/app/components/route/home/home.component.html
:
<!-- <app-layout>this is home</app-layout> -->
<p>home works!</p>
<app-route-layout>
<button (click)="jump()">Jump</button>
</app-route-layout>
src/app/components/route/home/home.component.ts
:
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor(private router: Router) { }
ngOnInit(): void {
}
jump() {
this.router.navigate(['/about', 'zhangsan'], {
queryParams: {
age: 18
}
});
}
}
12.8 路由模块
ng g m appRouting --flat=true
会放在app文件夹下面, 而不是单独创建一个文件
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LifecycleOnDestoryComponent } from './components/lifecycle/lifecycle-on-destory/lifecycle-on-destory.component';
import { LifecycleOnInitComponent } from './components/lifecycle/lifecycle-on-init/lifecycle-on-init.component';
import { HomeComponent } from './components/route/home/home.component';
import { AboutComponent } from './components/route/about/about.component';
import { NotFoundError } from 'rxjs';
import { NotFoundComponent } from './components/route/not-found/not-found.component';
import { NewsComponent } from './components/route/news/news.component';
import { CompanyComponent } from './components/route/company/company.component';
import { IndustryComponent } from './components/route/industry/industry.component';
// const routes: Routes = [
// //--- test for lifecycle-destroy--
// {
// path: '', // 根路径
// component: LifecycleOnDestoryComponent, // 显示 HomeComponent
// pathMatch: 'full'
// },
// {
// path: 'LifecycleOnInitComponent', // 显示 AboutComponent
// component: LifecycleOnInitComponent
// }
// //--- test for lifecycle-destroy--
// ];
// route
const routes: Routes = [
{
path: 'home', // 根路径
component: HomeComponent,
},
{
path: 'about/:name', // 显示 AboutComponent
component: AboutComponent
},
{
path: '',
// 重定向
redirectTo: 'home',
// 完全匹配
pathMatch: 'full'
// full是完全匹配,prefix是前缀匹配, 默认是prefix
},
{
path: 'news',
component: NewsComponent,
children: [
{
path: "company",
component: CompanyComponent,
outlet: "left"
},
{
path: "industry",
component: IndustryComponent,
outlet: "right"
}
]
},
{
path: '**',
component: NotFoundComponent
},
// order is important
];
@NgModule({
imports: [RouterModule.forRoot(routes, { useHash: true })],
exports: [RouterModule]
})
export class AppRoutingModule { }
src/app/app.module.ts
:
// BrowserModule 提供了启动和运行浏览器应用所必需的服务
// CommonModule 提供各种服务和指令,例如 ngIf 和 ngFor,与平台无关
// BrowserModule 导入了 ComonModule,又重新导出了 ComonModule,使其所有指令都可用于导入BrowserModule 的任何模块
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
// NgModule: Angular 模块装饰器,用于定义模块
import { AppRoutingModule } from './app-routing.module';
// 根组件
import { AppComponent } from './app.component';
import { SharedModule } from './shared/shared.module';
import { DataBindingComponent } from './components/component-template/data-binding/data-binding.component';
import { PropertyBindingComponent } from './components/component-template/property-binding/property-binding.component';
import { EventBindingComponent } from './components/component-template/event-binding/event-binding.component';
import { AccessNativeDomObjectsComponent } from './components/component-template/access-native-dom-objects/access-native-dom-objects.component';
import { TwoWayDataBindingComponent } from './components/component-template/two-way-data-binding/two-way-data-binding.component';
import { FormsModule } from '@angular/forms';
import { ContentProjectionComponent } from './components/component-template/content-projection/content-projection.component';
import { ErrorHandlingComponent } from './components/component-template/error-handling/error-handling.component';
import { GlobalStylesComponent } from './components/component-template/global-styles/global-styles.component';
import { StructuralDirectivesComponent } from './components/directive/build-in/structural-directives/structural-directives.component';
import { AttributeDirectivesComponent } from './components/directive/build-in/attribute-directives/attribute-directives.component';
import { CustomDirective } from './components/directive/custom/custom.directive';
import { PipeComponent } from './components/pipe/pipe/pipe.component';
import { CustomPipe } from './components/pipe/custom/custom.pipe';
import { ChildComponent } from './components/communication/child/child.component';
import { LifecycleOnInitComponent } from './components/lifecycle/lifecycle-on-init/lifecycle-on-init.component';
import { LifecycleOnUpdateComponent } from './components/lifecycle/lifecycle-on-update/lifecycle-on-update.component';
import { LifecycleOnDestoryComponent } from './components/lifecycle/lifecycle-on-destory/lifecycle-on-destory.component';
import { HomeComponent } from './components/route/home/home.component';
import { AboutComponent } from './components/route/about/about.component';
import { NavigationComponent } from './components/route/navigation/navigation.component';
import { RouteLayoutComponent } from './components/route/route-layout/route-layout.component';
import { NotFoundComponent } from './components/route/not-found/not-found.component';
import { NewsComponent } from './components/route/news/news.component';
import { CompanyComponent } from './components/route/company/company.component';
import { IndustryComponent } from './components/route/industry/industry.component';
// 调用NgModule装饰器, 告诉Angular 当前类表示的是Angular模块
@NgModule({
// 声明当前模块拥有哪些组建
declarations: [
AppComponent,
DataBindingComponent,
PropertyBindingComponent,
EventBindingComponent,
AccessNativeDomObjectsComponent,
TwoWayDataBindingComponent,
ContentProjectionComponent,
ErrorHandlingComponent,
GlobalStylesComponent,
StructuralDirectivesComponent,
AttributeDirectivesComponent,
CustomDirective,
PipeComponent,
CustomPipe,
ChildComponent,
LifecycleOnInitComponent,
LifecycleOnUpdateComponent,
LifecycleOnDestoryComponent,
HomeComponent,
AboutComponent,
NavigationComponent,
RouteLayoutComponent,
NotFoundComponent,
NewsComponent,
CompanyComponent,
IndustryComponent, // 属于当前模块的组件
],
// 声明当前模块依赖了哪些其他模块
imports: [
BrowserModule,
AppRoutingModule,
SharedModule,
FormsModule
],
// 声明服务的作用域, 数组中接收服务类, 表示该服务只能在当前模块的组件中使用
providers: [],
// 可引导组件, Angular 会在引导过程中把它加载到DOM中
bootstrap: [AppComponent],
})
export class AppModule { }
12.9 路由懒加载
路由懒加载是以模块为单位的。
-
创建用户模块
ng g m user --routing=true
一并创建该模块的路由模块 -
创建登录页面组件
ng g c user/pages/1ogin
-
创建注册页面组件
ng g c user/pages/register
-
配置户模块的路由规则
src/app/components/route/user/user-routing.module.ts
:
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LoginComponent } from './pages/login/login.component';
const routes: Routes = [
{
path: "login",
component: LoginComponent
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class UserRoutingModule { }
- 将用户路由模块关联到主路由模块
src/app/app-routing.module.ts
:
// route
const routes: Routes = [
{
path: 'home', // 根路径
component: HomeComponent,
},
{
path: 'about/:name', // 显示 AboutComponent
component: AboutComponent
},
{
path: '',
// 重定向
redirectTo: 'home',
// 完全匹配
pathMatch: 'full'
// full是完全匹配,prefix是前缀匹配, 默认是prefix
},
{
path: 'news',
component: NewsComponent,
children: [
{
path: "company",
component: CompanyComponent,
outlet: "left"
},
{
path: "industry",
component: IndustryComponent,
outlet: "right"
}
]
},
{
path: "user",
loadChildren: () => import('./components/route/user/user.module').then(m => {
console.log(m);
return m.UserModule
})
},
{
path: '**',
component: NotFoundComponent
},
// order is important
];
- 在导航组件中添加访问链接
src/app/components/route/navigation/navigation.component.html
:
<p>navigation works!</p>
<div>
<a routerLink="/home">home</a>
<br>
<!-- <a routerLink="/about" [queryParams]="{ name: 'sam' }">about</a> -->
<a [routerLink]="['/about','joe']">about</a>
<br>
<!-- <a routerLink="/news">News</a> -->
<a [routerLink]="['/news', {outlets: {
left: ['company'],
right: ['industry']
} }]">News</a>
<a routerLink="/user/login">login</a>
</div>
12.10 路由守卫
路由守卫会告诉路由是否允许导航到请求的路由。
路由守方法可以返回 boolean 或 Observable
import { Injectable } from "@angular/core"
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from
"@angular/router"
import { Observable } from "rxjs"
@Injectable({
providedIn: "root"
})
export class AuthGuard implements CanActivate {
constructor(private router: Router) {}
canActivate(): boolean | UrlTree {
1/ 用于实现跳转
return this.router.createUrlTree(["/user/login"] ])
11 禁止访问目标路由
return false
11 允许访问目标路由
12.10.1 CanActivate
检查用户是否可以访问某一个路由。
CanActivate 为接口,路由守卫类要实现该接口,该接口规定类中需要有 canActivate 方法,方法决定是否允许访问目标路由。
路由可以应用多个守卫,所有守卫方法都允许,路由才被允许访问,有一个守卫方法不允许,则路由不允许被访问。
创建路由守卫:ng g quard guards/auth
src/app/components/route/auth-gard.guard.ts
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthGardGuard implements CanActivate { // 这个CanActivate是一个接口,它有一个方法canActivate,这个方法返回一个boolean值,表示是否可以激活路由
// 注意大小写,这个接口的名字是CanActivate,而不是canActivate
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return true;
}
}
改成false就无法访问了
点击about就跳回home
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthGardGuard implements CanActivate { // 这个CanActivate是一个接口,它有一个方法canActivate,这个方法返回一个boolean值,表示是否可以激活路由
// 注意大小写,这个接口的名字是CanActivate,而不是canActivate
constructor(private router: Router) { }
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return this.router.createUrlTree(['/home']);
// return true;
}
}
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthGardGuard implements CanActivate { // 这个CanActivate是一个接口,它有一个方法canActivate,这个方法返回一个boolean值,表示是否可以激活路由
// 注意大小写,这个接口的名字是CanActivate,而不是canActivate
constructor(private router: Router) { }
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
// return this.router.createUrlTree(['/home']);
// // return true;
console.log(route); // 待激活路由快照
return false;
}
}
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthGardGuard implements CanActivate { // 这个CanActivate是一个接口,它有一个方法canActivate,这个方法返回一个boolean值,表示是否可以激活路由
// 注意大小写,这个接口的名字是CanActivate,而不是canActivate
constructor(private router: Router) { }
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
// return this.router.createUrlTree(['/home']);
// // return true;
console.log(state);
return false;
}
}
12.10.2 CanActivateChild
检查用户是否方可访问某个子路由。
创建路由守卫:ng g guard guards/admin
注意:选择 CanActivateChild,需要将箭头移动到这个选项并且敲击空格确认选择。
src/app/components/route/user/user-routing.module.ts
:
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LoginComponent } from './pages/login/login.component';
import { UserComponent } from './pages/user/user.component';
import { GuardCanActivateChildGuard } from '../guards/guard-can-activate-child.guard';
const routes: Routes = [
{
path: "login",
component: LoginComponent,
canActivateChild: [GuardCanActivateChildGuard],
children: [
{
path: "user",
component: UserComponent,
}
]
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class UserRoutingModule { }
src/app/components/route/guards/guard-can-activate-child.guard.ts
:
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivateChild, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class GuardCanActivateChildGuard implements CanActivateChild {
canActivateChild(
childRoute: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return false;
}
}
src/app/components/route/user/pages/login/login.component.html
:
12.10.3 CanDeactivate
检查用户是否可以退出路由。比如用户在表单中输入的内容没有保存,用户又要离开路由,此时可以调用该守卫提示用户。
src/app/components/route/guards/guard-can-deactivate.guard.ts
:
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanDeactivate, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
export interface canLeave {
canLeave: () => boolean;
}
@Injectable({
providedIn: 'root'
})
export class GuardCanDeactivateGuard implements CanDeactivate<canLeave> {
canDeactivate(
component: canLeave,
currentRoute: ActivatedRouteSnapshot,
currentState: RouterStateSnapshot,
nextState?: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
if (component.canLeave()) {
return true;
} else {
if (confirm("Are you sure you want to leave?")) {
return true;
} else {
return false;
}
}
}
}
src/app/components/route/guards/guard-can-deactivate/guard-can-deactivate.component.ts
:
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
@Component({
selector: 'app-guard-can-deactivate',
templateUrl: './guard-can-deactivate.component.html',
styleUrls: ['./guard-can-deactivate.component.css']
})
export class GuardCanDeactivateComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
form: FormGroup = new FormGroup({
username: new FormControl()
})
canLeave() {
return !this.form.get('username')!.dirty;
}
}
src/app/components/route/guards/guard-can-deactivate/guard-can-deactivate.component.html
:
<p>guard-can-deactivate works!</p>
<form [formGroup]="form">
<input type=" text" formControlName="username" />
<button>submit</button>
</form>
<app-navigation></app-navigation>
src/app/components/route/navigation/navigation.component.html
:
<p>navigation works!</p>
<div>
<a routerLink="/home">home</a>
<br>
<!-- <a routerLink="/about" [queryParams]="{ name: 'sam' }">about</a> -->
<a [routerLink]="['/about','joe']">about</a>
<br>
<!-- <a routerLink="/news">News</a> -->
<a [routerLink]="['/news', {outlets: {
left: ['company'],
right: ['industry']
} }]">News</a>
<br>
<a routerLink="/user/login">login</a>
<br>
<a routerLink="/candeactivate">guard-can-deactivate</a>
</div>
src/app/app-routing.module.ts
:
{
path: "candeactivate",
component: GuardCanDeactivateComponent,
canDeactivate: [GuardCanDeactivateGuard]
},
12.10.4 Resolve
允许在进入路由之前先获取数据,待数据获取完成之后再进入路由。
ng g resolver <name>
防止在网速比较的慢的情况下, 用户直接进入这个路由看到却是一个空的路由组件. 给用户错觉的这个页面出bug了.
src/app/components/route/resolver/get-name.resolver.ts
:
import { Injectable } from '@angular/core';
import {
Router, Resolve,
RouterStateSnapshot,
ActivatedRouteSnapshot
} from '@angular/router';
import { Observable, of } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class GetNameResolver implements Resolve<String> {
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<String> {
return new Promise(function (resolve) {
setTimeout(function () {
resolve("Name from resolver");
}, 3000);
})
}
}
src/app/components/route/home/home.component.ts
:
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor(private router: Router, private route: ActivatedRoute) { }
ngOnInit(): void {
console.log(this.route.snapshot.data['name']);
}
jump() {
this.router.navigate(['/about', 'zhangsan'], {
queryParams: {
age: 18
}
});
}
}
src/app/app-routing.module.ts
:
// route
const routes: Routes = [
{
path: 'home', // 根路径
component: HomeComponent,
resolve: {
name: GetNameResolver
}
},
src/app/components/route/user/pages/login/login.component.html
:
<p>login works!</p>
<a routerLink="/user/login/user">user</a>
<br>
<a routerLink="/home">home</a>
<router-outlet></router-outlet>
click home, 2s later