Angular路由
第二节:路由介绍
1.生成新项目
ng new 项目名 --routing : 注意 --routing的作用 .主模块、根组件引入route模块、组件。
2.Angular Route导航的四大对象:
Routes、RouteOutlet、Router、RouterLink、ActivatedRoute
routerProperty.png
- Routes: 进行路由的配置,使路由地址与组件相对应,并指定路由在哪个RouteOutlet中配置
- RouteOutlet:路由对应组件的展示位置
- Router: 在ts 文件进行路由的导航
- RouterLink: 在HTML文件进行路由的导航
- ActivatedRoute: 记录当前激活路由的对象,保存其信息,包括地址、组件、参数等。
3.app-routing.module.ts 配置Routes
const routes: Routes = [
{
path: '',
component: HomeComponent //Mac上通过option + enter 引入相应组件
},
{
path: 'stock',
component: StockComponent
},
{
path: '**',
component: Code404Component
}
];
注意:path属性不需要加‘/’。通配符配置,放在最后面,否则它后面的路由不会被加载,作用: 匹配找不到的其他路由。
并引入对应的组件:
import {StockComponent} from "./stock/stock.component";
import {HomeComponent} from "./home/home.component";
import {Code404Component} from "./code404/code404.component";
4.routerLink的应用:
在app.component.html文件中:
<a [routerLink]="['/']">主页</a>
<a [routerLink]="['/stock']">股票</a>
注意: 只在HTML页面设置跳转链接,可以完成跳转
5.router的应用:
(1).app.component.html文件中:
<button (click)="toStockDatail()">股票详情</button>
(2).app.component.ts文件中:
import {Router} from "@angular/router";
export class AppComponent {
constructor(private router: Router) { // 通过constructor引入Router
}
toStockDatail() {
this.router.navigate(['/stock']); // 导航到指定路由
}
}
注意:所有的组件都会在<router-outlet></router-outlet>后面展示
路由跳转后相应组件是加载在插座RouteOutlet的后面
6.针对不存在的路由的设置
通配符配置:app-routing.module.ts
...
{
path: '**',
component: Code404Component
}
...
注意: 通配符配置应放在路由配置的最后面,否则不会跳转其它的路由。
第三节 在路由中传递参数
1.链接中的查询参数中传递数据
app.component.html
<a [routerLink]="['/stock']" [queryParams]="{id: 1}">股票</a>
此时的路由为: localhost:4200/stock?id=1
接收数据:
stock.component.ts
(1)引入ActivatedRoute
import {ActivatedRoute} from "@angular/router";
constructor(private routeInfo: ActivatedRoute) {}
(2)定义数据:
private stockId: number;
(3)接收数据:
this.stockId = this.routeInfo.snapshot.queryParams['id'];
展示数据:
stock.component.html
{{stockId}}
2.在URL中传递
(1)修改路由定义:
app-routing.module.ts
{path: 'stock/:id',component: StockComponent}
(2)修改路由链接: app.component.html
<a [routerLink]="['/stock',1]">股票</a>
(3)接收参数: stock.component.ts
this.stockId = this.routeInfo.snapshot.params['id'];
3.在ts文件中传递数据:
app.component.ts
toStockDatail() {
this.router.navigate(['/stock', 2]);
}
注意: 接收参数方式与第二种一致
问题: 通过不同方式跳转到相同组件时,传递不同的数据,数据并不会被渲染。
所以:this.stockId = this.routeInfo.snapshot.params['id'];这个方式是由局限性的。只在第一次加载组件时,读取参数。
解决办法: 新的传递方式:参数快照 参数订阅
this.routeInfo.params.subscribe((params: Params) => this.stockId = params["id"]);
4.在路由配置中传递数据,而非在路径中传递静态数据:
(1)传递数据
{path: 'stock/:id',component: StockComponent,data: [{isPro: true}] }
(2)接收数据:
stock.component.ts:
private isPro:boolean;
this.isPro = this.routeInfo.snapshot.data[0]['isPro'];
第四节 路由的重定向
{ path: '', redirectTo: '/home', pathMatch: 'full' }
其中pathMatch: 'full' 是指当且仅当路由是''时,才会精准跳转到'/home'。
第五节 路由的嵌套: 子路由
1.在路由配置文件:app-routing.module.ts中配置子路由
{path: 'stock4/:id', component: Stock4Component,data:[{name: 'Smith'}], children: [
{path: '', component: SellerListComponent}, // 默认加载父组件路由时,加载该子组件。
{path: 'buyer/:id', component: BuyerListComponent} //当路由为/stock/1/buyer/id时,加载该子组件。
]}
2.在父组件添加插座:
<router-outlet></router-outlet>
3.在父组件添加跳转:
<button [routerLink]="['./']">卖家列表</button>
<button [routerLink]="['./buyer', 343]">买家列表</button>
// 注意:跳转的路径是以父组件为基准的,所以在路由前必须加上'./',否则就是以 '' 为基准了。
注意: (1)子路由是可以无限嵌套下去的。
(2)同一个组件可以有多个路由。
第六节 辅助路由:
1.定义插座:
<router-outlet></router-outlet>
<router-outlet name="aux"></router-outlet> // 为插座添加name
2.定义路由:
{
path: 'consult',
component: ConsultComponent,
outlet: 'aux' // 指定路由插座为‘aux’
}
该组件将会加载在辅助路由 'aux' 中
3.在辅助插座上显示相应组件:
<a [routerLink]="[{outlets: {primary: 'home',aux: 'consult'}}]">开始咨询</a>
// 设置路由指定的插座,同时基础路由为:home,primary可以不设置
// 辅助插座的指定路由为 'consult'
4.清空辅助插座内容:
<a [routerLink]="[{outlets: {aux: null}}]">结束咨询</a>
表示辅助插座aux加载的组件为空,即清空辅助插座内容
第七节 路由守卫
1.canActivate: 跳转到路由之前的情况判断
(1).定义canActivate路由守卫:
permission.guard.ts:
import {CanActivate} from "@angular/router";
export class PermissionGuard implements CanActivate {
canActivate() {
let hasPermission:boolean = Math.random()< 0.5;
if(!hasPermission) {
console.log('用户无权访问此股票详情');
}
return hasPermission;
}
}
(2).引入:
app.module.ts
...
providers: [PermissionGuard],
...
(3)应用:
app-routing.module.ts :
{
path: 'stock/:id',
component: StockComponent,
data: [{isPro: true}],
children: [
{path: '',component: BuyerListComponent},
{path: 'seller/:id',component: SellerListComponent}
],
canActivate: [PermissionGuard], // 应用
2.canDeactivate: 离开路由后的情况判断
(1) 定义canDeactivate路由守卫:
focus.guard.ts
import {CanDeactivate} from "@angular/router";
import {Stock4Component} from "../stock4/stock4.component";
export class FocusGuard implements CanDeactivate<Stock4Component> { // 指定需要保护的组件
canDeactivate(component:Stock4Component) {
if(component.focus()) { // 引入组件方法
return true;
}else {
return window.confirm('不关注吗?');
}
}
}
注意:因为是离开前的路由判断,所以可以利用组件信息
(2).引入:
app.module.ts
...
providers: [FocusGuard],
...
(3)应用:
app-routing.module.ts :
{
path: 'stock/:id',
component: StockComponent,
data: [{isPro: true}],
children: [
{path: '',component: BuyerListComponent},
{path: 'seller/:id',component: SellerListComponent}
],
canActivate: [FocusGuard], // 应用
(4)在stock4.component.ts中定义方法:
focus() {
return this.isFocus;
}
3.路由守卫resolve: 在跳转路由之前,获取路由数据,避免在没有获取数据之前,出现错误。
作用: 对数据进行判断,从而进行相应的跳转。
(1).准备工作:
stock.component.ts
将stock 数据转为对象:
private stock: Stock;
export class Stock {
constructor(public id: number, public name: string) {
}
}
(2).创建 stock的resolve守卫:
stock.resolve.ts
@Injectable() // 引入依赖注入
export class StockResolve implements Resolve<Stock> { // 引入Stock对象
constructor(private router: Router) { // 引入Router 模块
}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Stock | Observable<Stock> | Promise<Stock> {
let id = route.params['id']; // 接收传入数据
if (id == 1) {
return new Stock(1, 'IBM'); // 创建Stock 对象
} else {
this.router.navigate(['/home']); // 导航到home
}
}
(3).引入:
app.module.ts
providers: [StockResolve]
(4). 在路由定义中引入该路由守卫
resolve: {
stock: StockResolve
}
(5).在stock.component.ts中接收路由守卫处理后的数据
this.routeInfo.data.subscribe((data: { stock: Stock }) => {
this.stock = data.stock;
});