Angular 學習筆記(6) — Router
來到了框架的重頭戲:”Router”,靠著URL來達到顯示不同元件的目的,可說是在任何前端使用框架最重要的工具之一。
目標:學習使用Angualr框架。
Router使用
- 在app.module.ts中import RouterModule 、Routes,並用陣列設定與儲存routers的名稱:
設定不同的path,URL會根據route位置對應不同的元件,首頁也可以redirectTo: ’ /首頁路徑’
- 設定動態路徑(:id),抓取動態參數可讓url放入並顯示不同內容(如商品頁id)
- NgModule中註冊設定的routers:
- 在Html中使用 “router-outlet” 載入設定好的router元件:
- 在不同的url中,即會顯示不同的component內容:
- 透過插入<a routerLink>的方式傳送Url 、並切換component :
- 使用元件參數來動態製作路徑:
- 相對路徑(不帶’/’)會拼接父級路由,絕對路徑(帶’/’)是配置的完整路由,注意app.module.ts裡是否有設定path),才能使用。
- 在元件裡routerlink裡若非絕對路徑(沒加“/“相對路徑),path字串會追加在URl後放導致錯誤,使用路徑層層級關係,確保跳轉依據從根目錄url開始:
- 透過routerLinkActive=“[class名稱]”,觸發切當前頁面按鈕的外觀樣式:
- router.navigate()來透過用物件導入其他頁
- ActivatedRoute 獲取當前路徑,在constructor中建構使用route:
router.navigate()中加入{relativeTo:this.route}, 將導向的路經設定為對應的相對路徑,跟route同一個根目錄。
- 動態生成新路由route parms,顯示對應的子內容:
- 設定對應的路由參數
- 畫面根據傳遞的url 顯示對應的內容
- 為了能對應變動或新增的URL 產生的畫面,使用subscribe 訂閱監聽URL的路由參數:
- 不會新增資料,雖然已經在routerLink 中的指定路徑,但畫面沒有變化, 需要透過subscribe訂閱,抓取任何URL上的變化,來做畫面上的更新:
- 畫面隨著路由更新:
- 當componet切換時,可以取消訂閱 將paramsSubscription 設定為Subscription參數,作為當前路徑route
- Component切換消失後,將路經參數取消訂閱
- 當輸入一個未知或沒有建立的頁面,透過‘’redirectTo:’’ 來導入錯誤畫面:導向錯誤或未知頁面:
- 若一個route想重複使用(ex:錯誤畫面),只改變節點內容可以在 path 設定data將靜態資料傳入到route裡:
- 在TS載入route data的route data 有兩種方式:
- URL Hashmode,Url 加 “#”
QueryParams(?) & Fragment(#)
- 頁面內容可以隨著route 後方參數設定的變化而有所不同, 透過queryParams 和 fragment:
- 傳遞queryParams 和 fragment 的方式:
- Html傳遞a 連結:
2. method傳遞:
- 抓取route的參數,同樣使用subscribe獲取queryParams和 fragment的值:
- 透過subscribe更新params參數變化:
- 透過queryParamsHandling:’preserve’ 在跳轉畫面或元件時, 保留queryParams的參數並能產生對應的畫面:
- ‘merge’可以結合附加參數
this.router.navigate(
[PageLinkAlias['table-definition']],
{
queryParamsHandling: 'merge',
queryParams: { copyFrom: copiedUid },
},
);
Child (nested) Routes
- 整合相同根目錄的routes:
- 整理所有Routers 的 module:
- 建立app-routing.module.ts ,將所app.module 裡 routing設定移入檔案:
2. 引入@NgModule,exports RouterModule 至 APP Module,即可分開使用Router。
- createUrlTree 允許在 Router Guards 內回傳 UrlTree 物件,來達到轉址功能,一但轉址就會取消既有的瀏覽行為:參考文章
//** 登出過後,取消過去所有的瀏覽行為 **/
this.router.createUrlTree(['/auth']);
Guard-Service
守門員Guard被啟動時會觸發這個函式,並按照這個函式的執行結果所回傳的布林值,來判斷使用者可不可以造訪它所看守的路由router。 例如來模擬登入登出裝態。
- 登入範例:
- 建立兩層service 作保護(service要送入providers):
2. 在auth.service.ts,使用Promise非同步操作,建立完成或失敗後所產生的值,以及控制登入登出的boolean。
Promise 參考: https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Promise
3. 將設定好的service 引入至 auth-guard.service.ts看守路由:
canActivateChild()
防護子路徑child path,才能啟動,搭配canActivate:
套入 route module
- 編輯提醒範例:
當在編輯尚未完成切換畫面時,可以透過 canDeactivate()來把關去做提醒的功能:
canDeactivate()
canDeactivate用於確定是否可以離開某個路由,這個介面有泛型, 泛型的型別則是這個 Guard 要我們處理那個路由所設定的 Component 的型別。
Router module裡
Resolver
資料提供者類別可與路由器一起使用,以在導航期間解析資料,透過resolver將動態資料在啟用之前將資料解析。
確保routing載入:id時,若無資料對應的防護措施
- 建立resolver service
2. 設定解析內容:
3. 解析插入route data:
4. 元件初始化即可載入,在動態資料在啟用之前將資料解析
loadChildren #Lazy Loading
- 可用import module的方式設定router,減少載入時的記憶體大小 只要在對應頁面載入module,就不用一開始全部載入:
/** app-routing.module.ts **/
{
path: 'recipes',
loadChildren: () =>
import('./recipes/recipes.module').then((m) => m.RecipesModule),
},
/** app.module.ts **/
//不用再次import module 至 app.module
imports: [
...
// RecipesModule, //移除import的module
...
],
- 若想預先載入所有module,使用preloadingStrategy
/** app-routing.module.ts **/
@NgModule({
//preloadingStrategy預先載入所有module
imports: [RouterModule.forRoot(appRoutes,{preloadingStrategy:PreloadAllModules})],
exports: [RouterModule],
})
結語
學到Router時,個人認為是框架最奇妙的地方了。以往沒有框架時,必須把每頁功能塞滿龐大的程式碼,現在有了框架就可以動態引用參數,讓元件透過指定的參數進入不同的頁面,相當方便。設定更複雜、建立機制保護路徑,達成元件更靈活使用,相對地也必須更深入的學習使用方式。