Angular 路由快速教程

Photo by Harley-Davidson on Unsplash

声明

这个教程的目标是让初学者快速掌握 Angular 路由的基本使用方法,避免复杂

的概念影响对路由基本用法的认识,因此只涉及路由模块导入、路由匹配算

法、路由跳转指令,并不涉及守护路由、子路由,解析路由(resolver),路

由参数的获取等高级路由知识 。

前言

路由是一个 Web 应用不可缺少的一环, 路由的存在可以让用户对应用中感兴

趣的内容进行收藏方便下次访问。 在单页应用程序(SPA)中,路由必须由前

端来处理。Angualr 提供了功能强大的路由模块,可以帮我们完成复杂的页

面路由需求。

对于一个正常的 Web 应用来说,当一个路由发生时,会触发两个方面的变化,

一是浏览器中的地址会发生改变,二是页面局部或者全部会发生改变。

为了做到这两点,Angular 通过监听浏览器地址的改变来触发页面的渲染。这

其中的关键要数 “占位符” 和路由匹配的用法!

那就让我们开始吧~

准备工作

为了代码的可维护性,我们遵循 Angular 的最佳实践,把路由作为一个单独的

模块独立出来。将其命名为 AppRoutingModule,在 AppModule 中导入。

AppModule

接着,我们来编写这路由模块 AppRoutingModule 。同样为了简单起见,我

们先忽略路由匹配的具体内容,并用省略号代替。

AppRoutingModule

可以看到,这里我们使用到了 @angular/router 包下的 RouterModule 模块

和内置的路由匹配数组 Routes。有别于其他 Module 的导入方式,这里我们用

RouterModule.forRoot 来生成一个可导入的 Module。

forRoot 与 forChild

为什么要使用 forRoot ?这是因为 forRoot 方法除了能为 AppModule 提供

Angular 内建路由组件和指令之外,还能在应用的整个生命周期提供一系列统

一的路由服务(Service)。这些服务在某些我们需要对路由进行更加复杂操作

的场合就会用到。而在子模块中,我们只需使用到路由的组件和指令,就不用

再次导入这些服务,因此此时只要使用 forChild 方法即可。

话说回来,为什么这些服务只要导入一次而不用导入多次?这是因为 Angular

用特殊的设计模式——依赖注入来满足我们的需求。依赖注入的特点就是,一

旦我们在代码中声明了这些服务的构造方式,Angular 就会在服务的作用域内

通过注入器生成一个单一的实例/对象。

假设我们在 AppModule 提供了一组服务,然后在其他模块也导入了这组服

务,并且我们将这些模块导入到 AppModule 中。那么就可能导致这组服务被

多次注册。虽然最后通过服务标记(其实叫 token)可以对服务实例进行覆

盖。但是这样相当于初始化了多次实例。性能上有所损耗。

更糟糕的是,在某些场景下(LazyLoad)就会非常神奇的拥有了多份完全不同

副本的实例,导致在资源共享的场景下出现 Bug。

我在这篇文章中详解了 forRoot 针对的场景。

延伸阅读

Angular Router 源码中 forRoot 提供的服务可是 forChild 的好多倍。可以

点击这里看路由模块 forRoot 方法提供的服务。

万事具备

好了~ 现在我们就来探索 Angular 是如何解决路由中 Where(在哪里渲染)和

How(如何渲染或者说用什么组件渲染)的问题的。

Where——占位符

Angular 在路由变化时如何渲染页面,是整体还是局部?

我们用一个占位符(placeholder)或者说是一个指令 router-outlet 来做到。

app-component.html

在视图层我们添加了这个占位符之后,一旦路由发生改变,Angular 就会利用

在路由匹配中定义的组件来对这个位置进行渲染,达到页面整体或局部变化的

目的。很简单吧! 接下来让我们来解决 How 的问题。

How——路由匹配

在 Angular 中,路由匹配用来解决如何渲染页面的问题。

我们知道,Angular 中,通过功能将各个页面和对应的逻辑划分成一个又一个

的组件。而所谓路由匹配,就是在浏览器地址(路由)发生变化时,Angular

通过预先维护的一组路由——组件映射,来对页面的整体或者局部进行渲染。

AppRoutingModule

这边我们添加了三个路由匹配规则,profile、home 和 一个空路由。

这里的语法翻译成人类语言就是:

Profile 路由

路由前缀 profile 开头的路由,即形式为 localhost:4200/profie* 的路由,由组

件 ProfileComponent 负责渲染,替换掉 router-outlet 的位置。

Home 路由

路由前缀 home 开头的路由,即形式为 localhost:4200/home* 的路由,由组

件 HomeComponent 负责渲染,替换掉 router-outlet 的位置。

空路由

空路由,即形式为 localhost:4200/ 的路由 ,重定向到 /home。这里的重定向

意思是,把当前路由改成 home ,然后重新走一遍路由匹配表。

这里 redirectTo 就是重定向的意思。

细心的读者可能发现,这里对于空路由,除了 redirectTo 这条规则,我们还加

入了 pathMatch: full 这条规则。这是因为 Angular 中默认路由匹配的规则是

prefix(官方文档)。而空路由(”)默认是所有路由的前缀,所以,假如不加

full 的话,所有路由都会匹配到这条空路由上。这点切记。

当然,我在这篇详解路由匹配中对路由匹配机制有着更加详细的阐述,觉得不

过瘾的朋友可以看看。

最后一步!

所有的准备工作都已经完成!你就可以编写路由中涉及到的组件,来完成具体

的页面渲染逻辑了。我们只要在需要设置路由变化位置使用routerLink 指令就

能完成跳转啦。注意这里的 profile 要加上单引号哦,否则会被解析成组件的变

量而报错啦。

当然你也可以这样写,这样 profile 会被直接解析成字符串。

总结

路由的基本用法和一般的 Angular 内建模块有一些区别,主要在导入模块时需

要调用路由模块的 forRoot 方法来注入一些全局的服务。

同时针对路由的特点,Angular 利用 router-outlet 指令决定路由渲染 Where

的问题,利用路由匹配来解决 How 的问题。

在线例子

angular-router-simple-demo

参考链接

Angular Route 官方文档

Angular Router Module 源码

发表评论

电子邮件地址不会被公开。 必填项已用*标注