终於来到第三十天了~~~~!不过其实本系列不会在今天结束,我们的前端 app 丑得要命,也还没布署到 VM 上,目前都只在本机自 high,笔者一定不忘初衷,会坚持到把所有的东西都做完!(不过过完 30 天可能会慢一点发文,笔者累到快挂了XD)
因为 Angular 是单页应用(single page application, SPA)的框架,在单一个页的框架下要做到换页的效果,Angular 就必须根据使用者目前所巡览的位址来动态替换画面上的原件。截至目前,我们已经有了 4 个 component
之前都是暂时用注解/解开 selector 来显示不同的页面,今天,我们就来加上 routing(路由),之後就可以直接用 url 来控制页面的显示了。
我们自从在 Day24 提过这个模组之後,就再也没关心过他,现在它终於要派上用场了。这个档案里的程序码也非常简单,只有三个部分
要加入 routing 规则很简单,只要在上面的 routes 中加入 routing 规则的物件阵列就可以了,例如
const routes: Routes = [
{ path: '', redirectTo: '/ironman-list', pathMatch: 'full' },
{ path: 'ironman/:id', component: IronmanComponent },
{ path: 'ironman-list', component: IronmanListComponent },
{ path: 'ironman-add', component: IronmanFormAddComponent },
{ path: '**', component: IronmanListComponent }
];
上面的 redirectTo
是转址的规则设定,而且我们指定要完全符合才做转跳(pathMatch: 'full'
); path: '**'
是 Wildcard Route (万用路由),任何匹配不到的 url 都会显示 IronmanListComponent。请注意万用路由要放最後面,否则它後面的 routing 规则永远不会被用到。
如果我们巡览的 url 有匹配到 routes 的定义,那麽 Angular 就会把指定的 component 拿来塞进 app.component.html 中的 <router-outlet></router-outlet>
位置上,例如
设定好 routes 之後,我们就可以把之前写死在 app.component.html 的 component selector(<app-ironman>、<app-ironman-list>
)都删掉,留下<router-outlet></router-outlet>
就好。尝试在网址的地方输入不同的位址,可以看到我们的 app 会根据 routing 设定更换显示的 component
在上面的范例 routing 规则中,有一个比较特别、带了参数的规则{ path: 'ironman/:id', component: IronmanComponent }
,它代表了我们的 url 还带了一个名为 id 的参数,我们可以透过 Angular 的 ActivedRoute 类别帮我们取得这个参数,好让我们知道使用者要取得哪一笔资料,作法也非常简单,只要到 component.ts 引用并注入这个类别
// ironman.component.ts
// ...
import { ActivatedRoute } from '@angular/router';
// ...
constructor(private route: ActivatedRoute, private ironmanService: IronmanService) { }
接着就能用 route.paramMap 来取得 url 所带的参数值
this.route.paramMap.subscribe(map => {
const uid = map.get('id');
if (uid) {
this.ironmanService.getUserDetail(+uid) // 用加号把字串转成数字
.subscribe(resp => {
this.userInfo = resp;
});
}
});
上面的程序中,this.route.paramMap 也是一个 Observable 物件,所以我们必须订阅它,才能从它里面即时拿到参数的值。取得 id 的值之後用 id 查询使用者资料,然後换订阅 ironmanService 回传的 Observable,最後才把取得的资讯放到 userInfo 变数,让内嵌系结帮我们显示资讯。
虽然我们可以用手 key 网址直接到我们想要的页面,但是我们当然还是要提供方便一点的连结啦,现在我们就来介绍最简单的 routerLink。routerLink 这个 Directive 可以让宿主元素(host element)直接变成一个可以点的连结,所以只要用这个 directive,我们就不用限定一定要用 HTML 的 a tag,也不用自己写 JS/TS 用点击事件作超连结。不过,虽然它可以点、可以转跳页面,但是滑鼠指标不会变手指,所以要自己改一下 XD
<!-- app.component.html -->
<span routerLink="/ironman-list" routerLinkActive="router-link-active"
class="ironman-link-item">
List
</span>
<span routerLink="/ironman-add" routerLinkActive="router-link-active"
class="ironman-link-item">
Create
</span>
/* app.component.css */
.ironman-link-item {
cursor: pointer;
margin: 0px 10px 0px 10px;
}
.router-link-active {
font-weight: 700;
font-size: large;
text-decoration: underline;
}
上面的程序中,routerLink 这个 Directive 设定当这宿主容器被点击时,要巡览到哪一个路径,而 routerLinkActive 则是用来指定当这个 routing 被启用的时候,这个宿主元素要套用什麽样的 CSS 样式。
除了使用静态的页面连结,我们也可以透过程序来让我们的 app 转跳到其他页面,例如我们之前使用者列表的页面中,当使用者的 verified 属性是 1/true 的时候,我们会在表格中显示一个「编辑」按钮,我们可以让这个按钮触发一个事件,再用 Router 类别的 navigate() 方法,帮我们转跳到编辑这个使用者的页面
<!-- ironman-list.component.html -->
<!-- ... -->
<tr *ngFor="let user of userListFromApi">
<!-- ... -->
<td>
<button *ngIf="user.verified == 1" (click)="onEditUser(user.userId)">编辑</button>
</td>
</tr>
<!-- ... -->
// ironman-list.component.ts
// ...
import { Router } from '@angular/router';
// ...
// 在建构式注入 Router
constructor(private ironmanService: IronmanService, private router: Router) { }
// ...
onEditUser(id: number) {
this.router.navigate(['/ironman', id]);
}
// ...
改完~收工~我们的网站虽然丑,但是基本该有的功能都有得差不多了。
本系列不会在此结束,会坚持到把 Day01 提到的东西都做完(但可能会比发比较慢,已经累到要吃药了XD),竟请各位邦友持续关注!
图片来源:Bitsorbit CVE列表是指特定产品或系统中已识别的漏洞。与未发现或未知的漏洞相比...
前言 今天选择的是top 100 liked,并与linked list相关的题目:138. Cop...
以下内容皆参考 Backtrader 官网 昨天使用了 backtrader 将 shioaji 的...
上一篇我们提到了如何观察并且取出我们要的资料 也成功地把资料取出来了 这一篇我们将要对资料做最後的加...
Collaboration and augmentation are the foundation...