我覺得路由是 Angular 裡很重要的一部分,也是一個初學者比較不容易理解的部分,所以希望透過這七天的小小練習,會讓大家對路由有個初步的認識。
不過分了七天講是比較破碎了一點,而且也有些東西想再補充,就一併做個總結吧!
在 app-routing.module.ts
裡的 RouterModule.forRoot
函式裡加入 { enableTracing: true }
的參數。
如:
@NgModule({
imports: [RouterModule.forRoot(routes, {
enableTracing: true
})],
exports: [RouterModule],
providers: []
})
export class AppRoutingModule { }
還記得我們在路由(一)的時候有說過什麼是路由嗎?
拿 iT 邦幫忙的的網站來舉例好了,當我們在瀏覽器的網址列輸入
ithelp.ithome.com.tw
並按下 Enter 之後,就會看到 iT 邦幫忙的網站。然後如果我們要到其他地方,比如說「即時通知中心」。除了點擊「即時通知」的連結之外,我們其實可以直接在 iT邦幫忙的網址後面加上
/notifications
,像是這樣:ithelp.ithome.com.tw/notifications
。
上述這樣的方式其實就有點像是 PathLocationStrategy 這個路由策略,不過 PathLocationStrategy 這個路由策略的技術是建構在 history.pushState 之上,讓我們可以在路由狀態改變的時候,既能將其加入到瀏覽器的歷史裡,又不會真的向伺服器送出請求。
但是這個策略如果是用在低於 IE10 的瀏覽器上的話,還是會真的送出請求,導致頁面發生錯誤。而且這樣的路由策略會讓路由比較容易跟真正需要發出請求的路由混淆。
所以我們可以透過以下方式將預設使用的 PathLocationStrategy 改為使用 HashLocationStrategy :
@NgModule({
imports: [RouterModule.forRoot(routes, {
useHash: true
})],
exports: [RouterModule],
providers: []
})
export class AppRoutingModule { }
HashLocationStrategy 這個路由策略是採用 HTML 4 的標準 Hash 網址格式, IE 6 以上都能夠正常瀏覽,所以敬請放心使用。
不過官方是強烈推薦使用預設的 PathLocationStrategy 啦!主要是因為官方覺得這樣的 URL 更容易被使用者理解,且以後如果要使用 Server-Side Rendering 機制的話,可以無痛設定。
傳統頁面的超連結是透過使用 <a href=""></a>
完成的。
但在 Angualr 裡加了路由設定之後,我們可以透過以下幾種方式在我們的 <a></a>
裡加入超連結:
<ul>
<li><a [routerLink]="'/home'">Home</a></li>
<li><a [routerLink]="'/about'">About</a></li>
</ul>
2.用屬性綁定的方式傳入字串陣列
<ul>
<li><a [routerLink]="['/home']">Home</a></li>
<li><a [routerLink]="['/about']">About</a></li>
</ul>
<ul>
<li><a routerLink="/home">Home</a></li>
<li><a routerLink="/about">About</a></li>
</ul>
除此之外,我們還可以透過以下幾種方式來使用 routerLinkActive
,讓我們能夠很輕鬆地在導航路由時,在對應的 <a></a>
上加上我們所指定的樣式類別名稱:
<ul>
<li>
<a
[routerLink]="'/home'"
[routerLinkActive]="'active'"
>Home</a>
</li>
</ul>
<ul>
<li>
<a
[routerLink]="'/home'"
[routerLinkActive]="['active']"
>Home</a>
</li>
</ul>
<ul>
<li>
<a
[routerLink]="'/home'"
routerLinkActive="active"
>Home</a>
</li>
</ul>
routerLinkActive
其實很厲害,假設我們今天的路由結構是這樣:
所以當我們的路由是 /products
的時候,就會變成這樣:
那當路由是 /products/b
的時候呢?
會是這樣嗎?
不,其實會變成這樣:
因為 routerLinkActive
在比對路由的時候,會是這樣比對的:
/products
的時候,比對 /products
連結:成功。/products/b
的時候,比對 /products
連結:成功;比對 /products/b
連結:成功。所以 routerLinkActive
預設是會套用到上層路由的。
不過如果我們今天不想要連父層也一起套用的話,我們可以在父層的連結上多增加 [routerLinkActiveOptions]="{exact: true}"
的設定即可,像是:
<ul>
<li>
<a
[routerLink]="'news'"
routerLinkActive="active"
>News</a>
</li>
<li>
<a
[routerLink]="'products'"
[routerLinkActive]="'active'"
[routerLinkActiveOptions]="{exact: true}"
>Products</a>
</li>
<li>
<a
[routerLink]="['products', 'a']"
[routerLinkActive]="'active'"
>Product A</a>
</li>
</ul>
當我們的應用程式中加入了路由機制之後,會有個名為 Rotuer 的 Service 可以用。
使用方式:
export class LoginComponent implements OnInit {
constructor(private router: Router) { }
ngOnInit() {
}
}
注入這個 Service 後,我們可以從這個 Service 之中拿到所有的路由資訊、目前套用的路由與路由狀態。
除此之外,還可以透過使用這個 Service 來導頁,導頁的方式大致如下:
navigateByUrl
函式並傳入字串this.router.navigateByUrl('home');
navigate
函式並傳入字串陣列this.router.navigate(['home']);
navigate
函式並傳入字串陣列,且加上 { relativeTo: '當前路由' }
的參數表示要使用相對路徑的方式導頁export class LoginComponent implements OnInit {
constructor(
private router: Router,
private route: ActivatedRoute // 注入當前路由
) { }
ngOnInit() {
}
}
this.router.navigate(['..', 'home'], {
relativeTo: this.route
});
後面的參數物件裡的屬性除了
relativeTO
之外,還有很多很好用的參數,請直接參考官方文件的說明。
有時候我們會需透過路由傳遞參數,而傳遞參數的方法有兩種:
網址格式: http://localhost:4200/products?id=101
程式寫法:
this.router.navigate(['products'], {
queryParams: {
id: 101
}
});
Template 寫法:
<a [routerLink]="['products']" [queryParams]="{ id: 101 }">Prodcuts</a>
取得參數的方式:
export class ProductsComponent implements OnInit {
constructor(private route: ActivatedRoute) { }
ngOnInit() {
// 第一種方式(較推薦)
this.route.queryParams.subscribe((queryParams) => {
console.log(queryParams['id']);
});
// 第二種方式
console.log(this.route.snapshot.queryParams['id']);
}
}
網址格式:http://localhost:4200/products;id=101
this.router.navigate(['products', { id: 101 }]);
抑或是
<a [routerLink]="['products', { id: 101 }]">Products</a>
取得參數的方式:
export class ProductsComponent implements OnInit {
constructor(private route: ActivatedRoute) { }
ngOnInit() {
// 第一種方式
console.log(this.route.params['id']);
// 第二種方式
console.log(this.route.snapshot.params['id']);
}
}
由於要總結的事情有點多,所以還是分成兩天好了!
今天就先到這邊,明天繼續!!