2018年3月17日 星期六

【Ionic 3】頁面瀏覽機制(Navigation in Ionic 3)

Ionic雖以Angular做為流程運作的基礎,然而,在頁面瀏覽 (navigation) 機制方面,卻非直接採用Angular Router模組的運作方式,而是使用「堆疊」(navigation stack)的概念。


如圖,堆疊最上方的頁面元件是目前可視頁面。當要瀏覽其他頁面元件時,則使用push(),將該元件堆到堆疊上方即可(例如上圖的push(Page3))。相反的,回到前一頁,則使用pop()(如圖左,pop()後,回到Page2)。

Ionic頁面元件瀏覽係透過 NavController元件達成。因此各頁面都有import NavController元件,並在constructor中定義相關參數,以便進行push/pop等操作:
...
import { NavController } from 'ionic-angular'; ... export class HomePage { constructor(public navCtrl: NavController) { }

1. 範例:Two-Page Navigation
ionic g page指令可用來建立新頁面。在建立blank專案後,另外新增一個新頁面,便可用來示範瀏覽兩個頁面的情況。
不過,由於ionic 3支援lazy loading,新建頁面時,可以選擇該頁面是否要採用lazy loading(亦即瀏覽到該頁面,再做真正載入的動作);因此,新建頁面便有「是否採用」lazy loading的兩種情況。下列範例在首頁建立兩個按鈕,點選按鈕後分別對應到「採用」與「不採用」lazy loading的新頁面。
圖:關於我們(AppModule)按鈕不採用lazy loading
先以blank版型建立一個新專案:
ionic start navApp blank
接著以ionic g page分別建立新頁面元件about與credit,其中建立about時額外加上--no-module參數,credit頁面則不加參數:
cd navApp
ionic g page about --no-module
ionic g page credit
如下圖兩個頁面元件生成的檔案數量並不相同,credit元件多了一個module.ts檔:
圖:credit元件自成一個模組,--no-module參數使得about必須加入原有的AppModule
--no-module參數使得about元件生成時,不會產生module.ts檔。然而,因所有元件都必須屬於某個模組,因此接下來必須先將about加入專案預設模組AppModule中,如此才能在專案中使用about元件。另一方面,credit元件因有生成module.ts檔,已自屬一個模組,故只須小幅修改將credit元件export出來,便可於專案中使用該元件。至於,自動生成module.ts檔是為了能讓credit元件支援lazy loading(亦即使用到該元件才載入,而非專案一開始執行即載入)。

1.1 將about元件加入AppModule
由於about元件沒有模組,因此必須修改app.module.ts將之加入AppModule之中。
# app.module.ts
...
import { AboutPage } from '../pages/about/about';

@NgModule({
  declarations: [
    MyApp,
    HomePage,
    AboutPage
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage,
    AboutPage
  ],
  1. 第3行:如入import設定,AboutPage為about.ts檔內建立的類別名稱。
  2. 第9行:在@ngModule的declareations屬性內加入AboutPage元件。
  3. 第19行:在@ngModule的entryComponents屬性內加入AboutPage元件。
如此一來about元件便屬於AppModule模組,而可以用於其他元件之中,例如在HomePage元件裡,以push(AboutPage)加入瀏覽堆疊,完成頁面切換瀏覽的動作。

1.2 export credit類別
至於credit元件因有自己的模組檔案credit.module.ts,然因產生的模組檔並未將元件類別CreditPage設定於exports屬性內,故需自行加入,如第12-14行:(ionic CLI版本為3.19.1,測試時間為2018/3)
import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { CreditPage } from './credit';

@NgModule({
  declarations: [
    CreditPage,
  ],
  imports: [
    IonicPageModule.forChild(CreditPage),
  ],
  exports: [
    CreditPage
  ]
})
export class CreditPageModule {}
  1. 第2,10行:IonicPageModule用來封裝需要lazy loading的頁面元件,因此將模組內的CreditPage元件做為IonicPageModule.forChild()的參數。
  2. 第3行:credit.ts定義之元件名稱。
  3. 第12-14行:新增加之程式碼,將模組封裝之元件名稱export出去,才能在AppModule使用之。
另外,定義在credit.ts檔案的CreditPage元件類別,必須加上decorator指令@IonicPage(),才能成為lazy loading元件。credit.ts檔案內容如下:
import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';

@IonicPage()
@Component({
  selector: 'page-credit',
  templateUrl: 'credit.html',
})
export class CreditPage {

  constructor(public navCtrl: NavController, public navParams: NavParams) {
  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad CreditPage');
  }
}
1.3 完成首頁:HomePage
設定好兩個新的元件頁面後,接著修改HomePage頁面(pages/home/home.html),加入兩個按鈕,當按下按鈕時,將分別前往AboutPage頁面元件,以及CreditPage頁面元件:
<ion-header>
  <ion-navbar>
    <ion-title text-center>
      Demo:頁面瀏覽
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <button ion-button block outline (click)="NavToAboutOfAppModule()">
   關於我們(AppModule)
  </button>
  <button ion-button block outline (click)="NavToCreditOfAnotherModule()">
   Credit(Lazy loading)
  </button>
</ion-content>
  1. <ion-header>, <ion-content> 再加上<ion-footer>是頁面的最上層元素,此處使用ion-header, ion-content佈局。ion-header是表頭部份,ion-content則是主要內容區塊。
  2. <ion-header>內含<ion-navbar>,此元素會頁面瀏覽過程中會自動產生「返回按鈕」。而其內則可含標題<ion-title>。
  3. 第10行:ion-button是ionic擴充之按鈕指令(directive)。此指令有許多屬性可改變按鈕之外觀,例如此處 block outline等,詳細說明可參考官網Ionic API DOCS關於ion-button directive之段落
  4. 第10行:(click)是ionic-angular之事件繫結機制,將click事件綁定至NavToAboutOfAppModule()。
關於ionic 各種標籤用法細節,可參考Ionic官網UI Component,以及Ionic API Docs。CSS工具類別則在CSS Utilities
搭配home.html之home.ts檔案則必須定義兩個方法:NavToAboutOfAppModule()與NavToCreditOfAnotherModule(),在其內完成「瀏覽堆疊」之push()呼叫,如此才能切換至新增的兩個頁面元件。home.ts檔案如下
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';

import { AboutPage } from '../about/about';
import { CreditPage } from '../credit/credit';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

  constructor(public navCtrl: NavController) {
  }
  NavToAboutOfAppModule(){
    this.navCtrl.push(AboutPage);
  }
  NavToCreditOfAnotherModule(){
    this.navCtrl.push('CreditPage');
  }
}
  1. 第16行:this.navCtrl為NavController物件,可用來改變瀏覽堆疊,如切換至新頁面的push(),返回前頁面pop()、以及設定堆疊首頁的setRoot()。此處設定切換至新頁面AboutPage。注意push(AboutPage)參數未加引號。
  2. 第19行:同樣使用push()切換至新頁面,但因其為lazy loading模組元件,故呼叫push時,使用的參數是加了引號的'CreditPage'。或者在credit.ts的@IonicPage()加入name屬性設定,也可改用name屬性值,例如:
#credit.ts檔內
...
@IonicPage({
  name: 'page-credit'
})
....

#home.ts檔內
...
  NavToCreditOfAnotherModule(){
    this.navCtrl.push('page-credit');
  }
...
最後ionic serve執行時,若開啟「開發人員工具」檢視程式載入情形,便會發現只有載入about與home兩個頁面,credit因lazy loading之故,一開始並未載入,如下圖所示:
完整專案可參考https://github.com/leuowang/ionic-App.git裡之navApp資料夾。

沒有留言:

張貼留言