Day 2 安裝 VSCode & firstApp 解析 中最後帶到了點擊 Tabs 然後載入不同的 Page,最主要就是因為我們有設置 Route 。
首先我先準備一個 SideMenu 範本的 Ioinc 專案
ionic start demo2 sidemenu
然後 ionic serve 啟動後! 下面就是該 APP 。
他的 app.component.ts 主要做了顯示側欄選單。
appPages 變數是 menu 的 item,主要有 title、url、ico 三個欄位。
在 ngOnInit 的時候,依據 url 判斷哪個 item 被選到了。
import { Component, OnInit } from '@angular/core';
import { Platform } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.scss']
})
export class AppComponent implements OnInit {
public selectedIndex = 0;
public appPages = [
{
title: 'Inbox',
url: '/folder/Inbox',
icon: 'mail'
},
{
title: 'Outbox',
url: '/folder/Outbox',
icon: 'paper-plane'
},
{
title: 'Favorites',
url: '/folder/Favorites',
icon: 'heart'
},
{
title: 'Archived',
url: '/folder/Archived',
icon: 'archive'
},
{
title: 'Trash',
url: '/folder/Trash',
icon: 'trash'
},
{
title: 'Spam',
url: '/folder/Spam',
icon: 'warning'
}
];
public labels = ['Family', 'Friends', 'Notes', 'Work', 'Travel', 'Reminders'];
constructor(
private platform: Platform,
private splashScreen: SplashScreen,
private statusBar: StatusBar
) {
this.initializeApp();
}
initializeApp() {
this.platform.ready().then(() => {
this.statusBar.styleDefault();
this.splashScreen.hide();
});
}
ngOnInit() {
const path = window.location.pathname.split('folder/')[1];
if (path !== undefined) {
this.selectedIndex = this.appPages.findIndex(page => page.title.toLowerCase() === path.toLowerCase());
}
}
}
ion-menu-toggle 元件中 ngFor appPages 列出所有的 item。
ion-item 元件中 routerDirection 就純粹是頁面改變的動畫而已,有這三種 back、(預設)forward、root。
ion-item 元件中 [routerLink] 就是要被開啟的連結或頁面。
ion-router-outlet 元件則是依造現在 route 的狀態去動態塞入元件。
<ion-app>
<ion-split-pane contentId="main-content">
<ion-menu contentId="main-content" type="overlay">
<ion-content>
<ion-list id="inbox-list">
<ion-list-header>Inbox</ion-list-header>
<ion-note>hi@ionicframework.com</ion-note>
<ion-menu-toggle auto-hide="false" *ngFor="let p of appPages; let i = index">
<ion-item (click)="selectedIndex = i" routerDirection="root" [routerLink]="[p.url]" lines="none" detail="false" [class.selected]="selectedIndex == i">
<ion-icon slot="start" [ios]="p.icon + '-outline'" [md]="p.icon + '-sharp'"></ion-icon>
<ion-label>{{ p.title }}</ion-label>
</ion-item>
</ion-menu-toggle>
</ion-list>
<ion-list id="labels-list">
<ion-list-header>Labels</ion-list-header>
<ion-item *ngFor="let label of labels" lines="none">
<ion-icon slot="start" ios="bookmark-outline" md="bookmark-sharp"></ion-icon>
<ion-label>{{ label }}</ion-label>
</ion-item>
</ion-list>
</ion-content>
</ion-menu>
<ion-router-outlet id="main-content"></ion-router-outlet>
</ion-split-pane>
</ion-app>
這邊最主要就是 Routes 的設置。
我們可以看到,path: 'folder/:id',是戴了一個 id 的參數,然後載入 folder.module。
而 folder.module 中其實就只有一個頁面 folder.page 而已。在 folder.page 的文字也只是從 id 去抽換而已。
import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
const routes: Routes = [
{
path: '',
redirectTo: 'folder/Inbox',
pathMatch: 'full'
},
{
path: 'folder/:id',
loadChildren: () => import('./folder/folder.module').then( m => m.FolderPageModule)
}
];
@NgModule({
imports: [
RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
],
exports: [RouterModule]
})
export class AppRoutingModule {}
第一個 path 為 '' ,redirectTo 直接重新導向指定的 path。
pathMatch 則是告訴 router 怎麼樣去查找 route 。 這邊的 full 就是比較完整的路徑。
pathMatch 還可能的值為 prefix,他會比較部分。
第二個 path 為 'test',他會直接載入 TestComponent 元件。
第三個 path 為 'folder/:id',延遲載入的方式。一般情況下,如果直接用第二個 component 的方式,在 Ionic 載入的時候,該元件也會直接被載入,但如果你的專案很大,元件很多,在一開始載入的時候就會一次全部載入,導致APP 啟動效率差。用 loadChildren: () => import('./folder/folder.module').then( m => m.FolderPageModule) 的作法就可以把 folder.module 跟 app.module 拆開,當我們連接到 path 為 'folder/:id' 的時候在載入 folder.module 該模組。
第四個 path 為 'system',則是巢狀的寫法,children 底下又有 user 跟 permission。
'system/user' 他會載入 user.module
'system/permission' 他會載入 permission.module
const routes: Routes = [
{
path: '',
redirectTo: 'folder/Inbox',
pathMatch: 'full'
},
{
path: 'test',
component: TestComponent
},
{
path: 'folder/:id',
loadChildren: () => import('./folder/folder.module').then( m => m.FolderPageModule)
},
{
path: 'system',
children: [
{
path: 'user',
loadChildren: () => import('../system/user.module').then(m => m.UserPageModule)
},
{
path: 'permission',
loadChildren: () => import('../system/permission.module').then(m => m.PermissionPageModule)
}]
}
];
主要就是使用 ActivatedRoute。
this.activatedRoute.snapshot.paramMap.get('id');
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-folder',
templateUrl: './folder.page.html',
styleUrls: ['./folder.page.scss'],
})
export class FolderPage implements OnInit {
public folder: string;
constructor(private activatedRoute: ActivatedRoute) { }
ngOnInit() {
this.folder = this.activatedRoute.snapshot.paramMap.get('id');
}
}
在之前的例子,我們看到在元件上面加上 [routerLink]=['/tabs'] 的作法。
如果是執行事件之後,然後在轉跳呢?
主要就是使用 Router 。
this.router.navigate(['/tabs']);
帶參數
this.router.navigate(['/tabs'], { queryParams: { id: 1 } });
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-folder',
templateUrl: './folder.page.html',
styleUrls: ['./folder.page.scss'],
})
export class FolderPage implements OnInit {
constructor(private router: Router) { }
ngOnInit() {
this.router.navigate(['/tabs']);
this.router.navigate(['/tabs'], { queryParams: { id: 1 } });
}
}