この記事は、Ionic Advent Calendar 2018の14日目の記事です。
はじめに
Ionic v4ではページの遷移の方法が変わり、各フレームワーク用のルーターを使えるようになります。
この記事では利用者の多いと思われる Angular Router でのルーティングについて解説します。
基本
ページ遷移の元となる部分に<ion-router-outlet>
を設置します。このコンポーネントは@ionic/angular
専用です。Angularの<router-outlet>
と同等の機能に加え、画面遷移アニメーションの処理などが追加されています。
<ion-app>
<ion-router-outlet></ion-router-outlet>
</ion-app>
ルーティングは下の様に、各path
に対応するcomponent
を設定していきます。
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { UserListComponent } from './user-list/user-list.component';
import { UserDetailComponent } from './user-detail/user-detail.component';
const routes: Routes = [
{ path: '/', component: HomeComponent },
{ path: '/users', component: UserListComponent },
{ path: '/users/:id', component: UserDetailComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
あとはこのモジュールをAppModule
にインポートすればOKです。
ページを遷移するときは、
-
routerLink
ディレクティブ -
Router
サービス -
NavController
サービス(Ionic独自)
のいずれかを使用します。
<ion-header>
<ion-toolbar>
<ion-title>Page1</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
<ion-button routerLink="/page2" routerDirection="forward">page2</ion-button>
<ion-button (click)="gotoPage2ByRouter()">page2</ion-button>
<ion-button (click)="gotoPage2ByNavCtrl()">page2</ion-button>
</ion-content>
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { NavController } from '@ionic/angular';
@Component({
selector: 'app-page1',
templateUrl: 'page1.component.html',
styleUrls: ['page1.component.scss'],
})
export class Page1Component {
constructor(private router: Router, private navCtrl: NavController) {}
// AngularのRouterで遷移
gotoPage2ByRouter() {
this.router.navigateByUrl('/page2');
//this.router.navigate(['/page2']);
}
// IonicのNavControllerで遷移
gotoPage2ByNavCtrl() {
this.navCtrl.navigateForward('/page2');
}
}
/page2/:id
などURLのパスにパラメータを渡す場合は↓のように書きます。
// AngularのRouterで遷移
gotoPage2ByRouter() {
this.router.navigateByUrl(`/page2/${id}`);
//this.router.navigate(['/page2', id]);
}
// IonicのNavControllerで遷移
gotoPage2ByNavCtrl() {
this.navCtrl.navigateForward(`/page2/${id}`);
}
routerLink
ディレクティブのrouterDirection
プロパティは@ionic/angular
独自のもので、遷移時のアニメーションを指定できます。
<ion-button routerLink="/page2" routerDirection="forward">page2</ion-button>
なお、以下の値が設定可能です。
- forward(進む:デフォルト)
- back(戻る)
- root(差し替え, アニメーションなし)
- auto(自動)
遷移先のページで「戻る」ボタンを実装するときはion-back-button
を使いましょう。
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button text="戻る" defaultHref="/page1"></ion-back-button>
</ion-buttons>
<ion-title>Page2</ion-title>
</ion-toolbar>
</ion-header>
また、/users/:id
のようなパラメータを取得する場合は、ActivatedRoute
を使用します。
@Component({
selector: 'app-page2',
templateUrl: 'page2.component.html',
styleUrls: ['page2.component.scss'],
})
export class Page2Component implements OnInit {
constructor(private route: ActivatedRoute) {}
ngOnInit() {
const id = this.route.snapshot.paramMap.get('id');
}
}
応用
モジュールのLazy Loading
モジュールのLazy LoadingはWebアプリとして動かす場合は有用です。Ionic v3では@IonicPage
デコレータを使ってLazy Loadingしていましたが、v4からはAngular Routerの機能を使って
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [
{ path: '/', loadChildren: './home/home.module#HomeModule' },
{ path: '/users', loadChildren: './user-list/user-list.module#UserListModule' },
{ path: '/users/:id', loadChildren: './user-detail/user-detail.module#UserDetailModule' }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
の様に書くとモジュールをLazy Loadingしてくれます。
モジュールのPreloading
Cordovaで動かす場合は既に必要なデータが端末にインストールされているため(ページ遷移をスムーズに行うためにも)事前に読み込みを完了していることが望ましいです。
かといって、せっかくLazy Loading対応させたルーティング設定を今から書き直すのもちょっと...という場合はRouterModule.forRoot()
でPreloadAllModules
を指定しましょう。
RouterModule.forRoot({ routes, preloadingStrategy: PreloadAllModules });
メニュー
ion-menu
でメニュー画面を作り、コンテンツを表示する部分にion-router-outlet
を使います。
<ion-menu contentId="main">
<ion-header>
<ion-toolbar>
<ion-title>メニュー</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-menu-toggle>
<ion-item>メニュー1</ion-item>
<ion-item>メニュー2</ion-item>
</ion-menu-toggle>
</ion-list>
</ion-content>
</ion-menu>
<ion-router-outlet id="main"></ion-router-outlet>
ion-menu
を使う場合はion-router-outlet
にmain
属性またはid
の指定が必要です。
https://qiita.com/puku0x/items/a278e31d90164b535299
タブ
v4-beta.18から各タブがLazy Loadingできるようになりました。ルーティングの書き方は前述したLazy Loadingのものと同じで、v4-beta.17以前の名前付きion-router-outlet
と比べてシンプルになっています。
<ion-tabs>
<ion-tab-bar slot="bottom">
<ion-tab-button tab="home">
<ion-icon name="home"></ion-icon>
<ion-label>Home</ion-label>
</ion-tab-button>
<ion-tab-button tab="about">
<ion-icon name="information-circle"></ion-icon>
<ion-label>About</ion-label>
</ion-tab-button>
<ion-tab-button tab="contact">
<ion-icon name="contacts"></ion-icon>
<ion-label>Contact</ion-label>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
↑HTML側はion-tab-button
のtab
属性に各タブのパスを書くだけです。
各タブのルーティングをchildren
に書いていきます。redirectTo
の部分は必須です。
const routes: Routes = [
{
path: '',
redirectTo: '/tabs/home',
pathMatch: 'full'
},
{
path: 'tabs',
component: TabsComponent,
children: [
{
path: 'home',
children: [
{
path: '',
loadChildren: './home/home.module#HomeModule'
}
]
},
...
]
}
];
タブ内でページ遷移する場合、v4-beta.17以前では親モジュール(<ion-tabs>
のあるところ)にルーティングを書いていましたが、v4-beta.18以降は各タブのモジュールに書けばよくなったのでわかりやすくなりました。
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ContactComponent } from './contact.component';
const routes: Routes = [
{
path: '',
component: ContactComponent
},
{
path: 'detail',
loadChildren: './contact-detail/contact-detail.module#ContactDetailModule'
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ContactRoutingModule {}
今後変更されそうな部分
ページ遷移時の引数
Angular v7.2でルーターによる遷移時に任意のデータを渡せるようになるそうです。
おわりに
v3までのPush/Popで遷移する方式と違い、v4は自分でルーティングを組む必要があるので敷居がちょっと上がった感じはありますが、Webアプリからスマホアプリ、PWAまでカバーできるのでIonicは魅力的なフレームワークです。
普段からSPA開発に慣れていて、スマホアプリへの展開も考えている場合などには良い選択肢になると思います。
AngularとIonic両方追いかけるのは大変ですが、是非とも使いこなせるようになりたいですね。