路由简介

在上一篇前端-angular(组件)中我们说到,一个angular应用中会存在很多个组件,组件之间的关系就如下图,是一个树形结构,树的根节点就是angular应用中必有得AppComponent,他是angular应用的入口。 image.png 如上图所示中,组件与组件之间通过一定关系组成树形结构,而路由就是这个关系。路由是一组规则,他决定了URL的变化对应着哪些状态的变化,以及页面视图的变化。 在angular中,路由非常重要,组件的实例化与销毁甚至某些生命钩子的调用都与路由有关。 image.png 根据上图我们得到下表: |URL|对应显示组件| |-------|-------| |/|AppComponent| |/a|ComponentA| |/a/a1|ComponentA1| |/a/a2|ComponentA2| |/b|ComponentB| |/b/b1|ComponentB1| |/b/b2|ComponentB2| |/c|ComponentC| |/c/c1|ComponentC1| |/c/c2|ComponentC2| 现在我们用代码来实现这个路由效果

路由配置

我们在前端-Angular(搭建开发环境)一文中已经创建了一个名为firstAngular的项目,现在我们用webstorm打开这个项目并打开APP路由配置文件(app-routing.mudule.ts)。

import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';


const routes: Routes = [];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {
}

首先我们创建a、a1、a2、b、b1、b2、c、c1、c2这九个组件,如何创建组件在前端-angular(组件)一文中已经写过。 创建完成后,整个项目目录结构如下 image.png 现在,我们修改APP路由配置文件(app-routing.mudule.ts)代码如下以达到预期的路由效果

import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {AppComponent} from './app.component';
import {AComponent} from './a/a.component';
import {A1Component} from './a/a1/a1.component';
import {A2Component} from './a/a2/a2.component';
import {BComponent} from './b/b.component';
import {B1Component} from './b/b1/b1.component';
import {B2Component} from './b/b2/b2.component';
import {C1Component} from './c/c1/c1.component';
import {C2Component} from './c/c2/c2.component';
import {CComponent} from './c/c.component';


const routes: Routes = [
  {
    path: 'a',
    component: AComponent,
    children: [
      {path: 'a1', component: A1Component},
      {path: 'a2', component: A2Component},
    ]
  },
  {
    path: 'b',
    component: BComponent,
    children: [
      {path: 'b1', component: B1Component},
      {path: 'b2', component: B2Component},
    ]
  },
  {
    path: 'c',
    component: CComponent,
    children: [
      {path: 'c1', component: C1Component},
      {path: 'c2', component: C2Component},
    ]
  },
  {
    path: '', component: AppComponent
  },
  {
    path: '**',
    component: AComponent
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {
}

如上代码中,我们可以看见,整个路由配置也是一个树状结构,就相当于我们用angular的代码来实现了本文第一个图一样的组件树状结构。其中一对{}就代表一个路由规则

  • path 代表一个路由规则所匹配的URL路径,由于路由配置是一个树状结构,所以会在其前面添加父级path,比如a1路由规则最终所匹配的URL路径为a/a1。当path值设置为**时代表此为一个通配路径规则,他会匹配所有未与其他路由规则匹配上的URL。
  • component 代表此路由对应显示的组件
  • children 代表路由规则的所有子路由,其内部也是一堆路由配置。但其内配置的所有子路由都是匹配父路由/子路由的路径,如a/a1。 现在,我们试着访问一下http://localhost:4200/a,A组件显示正常,效果如下 image.png 我们再访问一下http://localhost:4200/a/a1,我们发现A1组件并未正常显示。 image.png 路由规则的顺序是非常重要的,它符合就近原则,当浏览器的URL变化时,Router会从上到下依次查找对应的路由贵州,找到符合的规则后,就决定显示那个组件,那么后面的路由就被"短路"了,例如,如果把通配符路由放在第一个,那么无论路由怎么变化,在他后面的路由都失去了意义,因为不论怎么变化,他都是第一个符合规则的,所以它通常要放在最后一个。

路由插座

对比app.component.html和a.component.html的代码我们可以发现,app.component.html中存在额外的一行代码

<router-outlet></router-outlet>

修改a.component.html的代码如下:

<p>a works!</p>
<router-outlet></router-outlet>

再次访问http://localhost:4200/a/a1,A1组件正常显示。 image.png 路由插座也就是router-outlet标签,他是angular路由体系中不可缺少的重要组成部分。 RouterOutlet 是一个来自路由模块中的指令,它的用法类似于组件。 它扮演一个占位符的角色,用于在模板中标出一个位置,路由器将会把要显示在这个出口处的组件显示在这里。 我们需要时刻记住路由是一个树状结构,路由器每匹配到一个路由规则且此路由规则定义了要显示的组件时,路由插座就会被占用且无法被更改,除非路由再次改变。也就是说在我们的路由树状图中,每个存在子组件的组件都应该包含一个路由插座router-outlet标签以使得子组件可正常显示。如下图 image.png

路由跳转

在上面的内容中,我们所有的页面都是通过手动在浏览器输入URL进行访问的,但大多数时候,我们仅会通过输入地址的方式访问项目的首页。而其后的所有页面都是通过项目内部自行跳转。而路由跳转常用如下两种方式

  1. routerLink
  2. Router
<p>a1 works!</p>
<a routerLink="/a/a2">跳转a2</a>

Router

Router是angular提供的导航及操纵URL也就是进行路由跳转的一个服务。

  constructor(private router: Router) {
  }

  ngOnInit() {
  }

  navigate() {
    this.router.navigateByUrl('/a/a2');
  }

路由参数

当我们进行页面跳转时,我们可能需要携带一些参数到下一个页面,这个时候我们通过路由来携带参数。

routerLink方式跳转

<p>a1 works!</p>
<a routerLink="/a/a2" [queryParams]="{a:'asd'}">跳转a2</a>

如上代码中相对于路由跳转多了一个queryParams。

Router方法跳转

  constructor(private router: Router) {
  }

  ngOnInit() {
  }

  navigate() {
    this.router.navigate(['/a/a2'], {queryParams: {a: 'asd'}});
  }

如上代码所示,navigate方法有一个可选参数,其类型为NavigationExtras,可通过其完成路由传值。

  • queryParams 通过queryParams可以路由的查询参数,如上代码中最终链接为"a/a2?a=asd"。

路由参数取值

  constructor(private ac: ActivatedRoute) {
    this.ac.snapshot.queryParamMap.get('a');
  }
  • ActivatedRoute ActivatedRoute是angular提供的服务,其表征当前激活的路由,可通过他来获取当前路由的路径和参数等很多有用的信息,包括: image.png

路由事件

在每次导航中,Router 都会通过 Router.events 属性发布一些导航事件。这些事件的范围涵盖了开始导航到结束导航。

image.png

image.png

路由守卫