购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

4.7 使用路由

本节将实现路由功能。

通过路由器来将不同的URL映射到不同的模块。

4.7.1 路由的用处

路由的用处在于,通过统一的代码或者配置,来将URL映射到指定的模块。这样就能够显式地知道哪些模块会来处理发生在哪些URL的请求。

4.7.2 创建AppRoutingModule

Angular 的最佳实践之一就是在一个独立的顶级模块中加载和配置路由器,它专注于路由功能,然后由根模块AppModule导入它。

按照惯例,这个模块类的名字叫作AppRoutingModule,并且位于src/app目录下的app-routing.module.ts文件中。

使用Angular CLI生成它。

其中,

● “--flat”把这个文件放进了src/app目录中,而不是单独的目录中。

● “--module=app”告诉Angular CLI把它注册到AppModule的imports数组中。

在控制台上,可以看到如下生成的文件:

其中,src/app/app-routing.module.ts文件是这样的:

通常我们不会在路由模块中声明组件,所以可以删除@NgModule.declarations,并删除对 CommonModule的引用。

我们将会使用 RouterModule中的Routes类来配置路由器,所以还要从@angular/router 库中导入RouterModule和Routes。

添加一个@NgModule.exports数组,在其中放上RouterModule。导出RouterModule,让路由器的相关指令可以在AppModule的组件中使用。

此刻的AppRoutingModule是这样的:

1. 添加路由定义

路由定义会告诉路由器,当用户单击某个链接,或者在浏览器地址栏中输入某个URL 时,要显示哪个视图。

典型的Angular路由(Route)有两个属性。

● path:用于匹配浏览器地址栏中URL的字符串。

● component:当导航到此路由时,路由器应该创建哪个组件。

如果我们希望当URL为“localhost:4200/users”时,就导航到UsersComponent,那么,首先要导入UsersComponent,以便能在Route中引用它;然后定义一个路由数组,其中的某个路由是指向这个组件的。

完成这些设置之后,路由器将会把 URL 匹配到“path:'users'”,并显示 UsersComponent。

2.RouterModule.forRoot()

我们必须首先初始化路由器,并让它开始监听浏览器中的地址变化。

把RouterModule添加到@NgModule.imports数组中,并用routes来配置它。只要调用 imports数组中的RouterModule.forRoot()函数就行了。

这个方法之所以被叫作forRoot(),是因为我们要在应用的顶级配置这个路由器。forRoot()方法会提供路由所需的服务提供商和指令,还会基于浏览器的当前URL执行首次导航。

所以,此刻的AppRoutingModule的代码如下:

4.7.3 添加路由出口

打开AppComponent的模板文件app.component.html,把<app-users>标签替换为 <router-outlet>标签。

之所以移除<app-users>标签,是因为只有当用户导航到这里时,才需要显示UsersComponent。

<router-outlet>标签会告诉路由器要在哪里显示路由到的视图。

之所以能在AppComponent中使用RouterOutlet,是因为在AppModule中导入了AppRouting Module,而在AppRoutingModule中导出了RouterModule。

执行“ng serve”命令以启动应用。访问“http://localhost:4200”,效果如图4-14所示。

图4-14 运行效果

页面中显示了应用的标题,但是没有显示用户列表。

在浏览器的地址栏中,我们把URL改为“http://localhost:4200/users”,由于路由到了 UsersComponent模块,因此能够去到熟悉的主从结构的用户显示界面,效果如图4-15所示。

图4-15 运行效果

4.7.4 添加路由链接

除把路由的 URL 粘贴到地址栏外,用户应该通过单击链接进行导航。

添加一个<nav>标签,并在其中放置一个<a>标签,当单击<a>标签时,就会触发一个到UsersComponent 的导航。修改过的AppComponent的模板文件src/app/app.component.html如下。

代码 4-16 app/app.component.html

routerLink属性的值为“/users”,路由器会用它来匹配出指向UsersComponent的路由。routerLink是RouterLink指令的选择器,它会把用户的单击转换为路由器的导航操作。它是 RouterModule中公开的另一个指令。

另外,为了让显示更加美观,我们需要在 src/app/app.component.css 文件中添加如下样式。

代码 4-17 app/app.component.css

执行“ng serve”命令以启动应用。访问“http://localhost:4200”,页面中会显示应用的标题和指向用户列表的链接,但是并没有显示用户列表。效果如图4-16所示。

单击这个“Users”链接,地址栏变成了“http://localhost:4200/users”,并且显示出用户列表。效果如图4-17所示。

图4-16 运行效果

图4-17 运行效果

4.7.5 添加仪表盘视图

在有多个视图时,使用路由会更有价值。不过,目前还只有一个用户列表视图。我们将添加一个仪表盘视图,来进行多个视图之间的切换。

使用Angular CLI添加一个DashboardComponent。

从控制台中可以看到生成了如下文件:

Angular CLI生成了DashboardComponent的相关文件,并把它声明到AppModule中。

1. 修改 dashboard.component.html 文件

修改 dashboard.component.html 文件如下。

代码 4-18 app/dashboard/dashboard.component.html

这个模板用来表示由用户名字链接组成的一个阵列。

●*ngFor复写器为组件的users数组中的每个条目创建了一个链接。

● 这些链接被dashboard.component.css中的样式格式化成了一些色块。

2. 修改 dashboard.component.ts 文件

DashboardComponent类和 UsersComponent 类很像,代码如下。

代码 4-19 app/dashboard/dashboard.component.ts

其中,

● DashboardComponent定义了一个users数组属性。

● DashboardComponent的构造函数希望Angular把UserService注入私有的userService属性中。

● 在ngOnInit()生命周期钩子中调用了getUsers()函数。

● getUsers()函数中的slice()方法的作用是把要显示的用户数量缩减为4个(取第2、3、4、5个)。

3. 添加仪表盘到路由

要导航到仪表盘,需要在路由器中有一个相应的路由。

把DashboardComponent导入AppRoutingModule中。

把一个指向DashboardComponent的路由添加到AppRoutingModule.routes数组中。

完整代码如下。

代码 4-20 app/app-routing.module.ts

4. 添加默认路由

在应用启动时,浏览器的地址栏指向了网站的根路径。它没有匹配到任何现存路由,因此路由器也不会导航到任何地方。<router-outlet>下方是空白的。

要让应用自动导航到这个仪表盘,请把下列路由添加到 AppRoutingModule.Routes 数组中。

这个路由会把一个与空路径“完全匹配”的 URL 重定向到路径为“/dashboard”的路由。

刷新浏览器之后,路由器加载了 DashboardComponent,并且在浏览器的地址栏中会显示出“/dashboard”,效果如图4-18所示。

图4-18 运行效果

完整代码如下。

代码 4-21 app/app-routing.module.ts

5. 添加仪表盘链接

在页面顶部导航区增加仪表盘链接,以便实现各个链接在DashboardComponent和 UsersComponent之间来回导航。

修改AppComponent的模板文件src/app/app.component.html。

代码 4-22 app/app.component.html

刷新浏览器,就能通过单击这些链接在这两个视图之间自由导航了。效果如图4-19所示。

图4-19 运行效果

4.7.6 导航用户详情

UserDetailComponent用于显示所选用户的详情。但目前的UserDetailComponent只能在 UsersComponent的底部看到。

接下来,我们要实现通过3种途径看到这些用户详情。

● 通过在仪表盘中单击某个用户。

● 通过在用户列表中单击某个用户。

● 通过把一个“深链接”URL粘贴到浏览器的地址栏中来指定要显示的用户。

1. UsersComponent 中删除用户详情

当用户在UsersComponent中单击某个用户条目时,应用应该能导航到UserDetailComponent,从用户列表视图切换到用户详情视图。用户列表视图将不再显示,而用户详情视图将要显示出来。

打开UsersComponent的模板文件users/users.component.html,并从底部删除 <app-user-detail>标签。

2. 添加用户详情到路由

接下来要将用户详情添加到路由中去。只要访问“~/detail/11”URL,就能导航到id为11的用户的详情视图。实现方式如下。

打开AppRoutingModule(src/app/app-routing.module.ts),并导入UserDetailComponent。

然后把一个参数化路由添加到AppRoutingModule.routes数组中,它要匹配指向用户详情视图的路径。

path中的冒号(:)表示“:id”是一个占位符,它表示某个特定用户的id。

此刻,应用中的所有路由都就绪了。完整代码如下。

代码 4-23 app/app-routing.module.ts

3. 添加用户详情到 DashboardComponent

路由器中已经有一个指向UserDetailComponent的路由了,修改仪表盘中的用户链接,让它们通过参数化的用户详情路由进行导航。

通过在*ngFor复写器中使用Angular的插值表达式,来把当前迭代的user.id插入每个routerLink中。

4.UsersComponent 中的用户链接

UsersComponent中的这些用户条目都是<li>标签,它们的单击事件都绑定到了组件的onSelect()方法中。现在需要做如下修改。

代码 4-24 app/users/users.component.html

还要修改私有样式表(users.component.css文件),让列表恢复到以前的外观。修改后的样式代码如下。

代码 4-25 app/users/users.component.css

5. 移除冗余代码

虽然UsersComponent类仍然能正常工作,但onSelect()方法和selectedUser属性已经没用了,最好把它们清理掉。

下面是删除了冗余代码之后的类(users.component.ts)。

代码 4-26 app/users/users.component.ts

4.7.7 支持路由的UserDetailComponent组件

以前,父组件UsersComponent会设置UserDetailComponent.user属性,然后UserDetailComponent就会显示这个用户。

现在,UsersComponent已经不会那么做了。当前路由器会在响应形如~/detail/11的URL 时创建UserDetailComponent。

UserDetailComponent 需要从一种新的途径获取要显示的用户。

● 获取创建本组件的路由。

● 从这个路由中提取出 id。

● 通过UserService从服务器上获取具有这个 id 的用户数据。

在UserDetailComponent 中先添加下列导入语句。

然后把ActivatedRoute、UserService和Location服务注入构造函数中,并将它们的值保存到私有变量里。

其中,

● ActivatedRoute 中保存着到这个 UserDetailComponent 实例的路由信息。这个组件对从URL中提取的路由参数感兴趣。其中的id参数就是要显示的用户的id。

● UserService从远程服务器上获取用户数据,本组件将使用它来获取要显示的用户。

● Location是Angular的一个服务,用来与浏览器打交道。稍后,我们就会使用它来导航回上一个视图。

1. 从路由参数中提取 id

修改 user.service.ts文件,在ngOnInit()生命周期钩子中调用getUsers(),代码如下:

route.snapshot是一个路由信息的静态快照,抓取自组件刚刚创建完毕之后。

paramMap是一个从URL中提取的路由参数值的字典。id对应的值就是要获取的用户的id。

路由参数总是一个字符串。JavaScript 中的“+”操作符会把字符串转换成数字,因为用户的id就是数字类型的。

刷新浏览器,出现了一个编译错误,因为UserService中没有一个名为“getUser()”的方法。下面就添加它。

2. 添加 UserService.getUser() 方法

在UserService中添加如下的getUser()方法。

注意:反引号(`)用于定义JavaScript的模板字符串字面量,以便嵌入id。

像getUsers()一样,getUser()也有一个异步函数签名。它用RxJS的of()函数返回一个Observable 形式的模拟用户数据。

提示:

我们将来可以用一个真实的HTTP请求来重新实现getUser(),而不用修改调用了它的 UserDetailComponent。

3. 运行

刷新浏览器,应用又恢复正常了。可以在仪表盘或用户列表中单击一个用户来导航到该用户的详情视图。

如果在浏览器的地址栏中粘贴了“localhost:4200/detail/11”,那么路由器也会导航到 id为 11 的用户(Way Lau)的详情视图。效果如图4-20所示。

图4-20 运行效果

4. 添加“返回”按钮

通过单击浏览器中的“后退”按钮,可以回到用户列表或仪表盘视图,这取决于我们是从哪里进入详情视图的。

现在,我们要在UserDetail视图中也添加这样一个按钮。我们把该“返回”按钮添加到组件模板的底部,并且把它绑定到组件的goBack()方法中。

修改user-detail.component.html,添加如下代码:

在组件类中添加一个goBack()方法,利用以前注入的Location服务在浏览器的历史栈中后退一步。

修改user-detail.component.ts,添加如下代码:

刷新浏览器,并开始单击界面上的按钮,用户能在应用中导航:从仪表盘到用户详情再回到仪表盘,从用户列表到用户详情再回到用户列表。效果如图4-21所示。

图4-21 运行效果 +T9M8iCVvotuj1KoYi7NSyDMA3kKLwcENf8jDnpVHaDGmcSz6iYKTkoepwXYdPW1

点击中间区域
呼出菜单
上一章
目录
下一章
×