Ionic + Angular で DRY な共有ナビゲーションコンポーネントを実装する方法
Ionic と Angular を使って共通ナビゲーションを実装する方法を解説。standalone コンポーネントを活用し、コードの重複を避けながら保守性の高いタブバーを実現する DRY な手法を紹介します。
目次
モバイルアプリ開発において、複数のページで同じナビゲーション要素を表示することはよくあります。しかし、各ページで同じコードを繰り返し記述するのは保守性の観点から好ましくありません。
今回は、Ionic と Angular の standalone コンポーネント機能を使って、DRY(Don’t Repeat Yourself)原則に基づいた共有ナビゲーションコンポーネントの実装方法をご紹介します。
ツールバーコンポーネントを1つにまとめる
当初、各ページのテンプレートに直接 ion-tab-bar
を記述していました。
<!-- 各ページで同じコードを繰り返し -->
<ion-tab-bar slot="bottom">
<ion-tab-button tab="dashboard" href="/forecasts/dashboard">
<ion-icon aria-hidden="true" name="grid-outline"></ion-icon>
<ion-label>ダッシュボード</ion-label>
</ion-tab-button>
<!-- 他のタブボタン... -->
</ion-tab-bar>
動作をチェックする面では問題なかったのですが、開発を続ける上で次のような問題が浮上してきました。
- コードの重複により同じコードを複数のページで記述する必要がある
- 保守性が悪く、変更時に全ページを修正しなければならない
- standalone コンポーネントで必要なインポートが不足し、型エラーが発生する
href
では Angular ルーティングが動作しない
共有コンポーネントで問題を解決する
対策として、Angularの共通コンポーネントを作成する方法を試しました。
まず、Angular CLI を使って共有コンポーネントを生成します。今回は実験要素が強かったため、テストコードを省略しています。
npx ng generate component shared/bottom-tabs -- --skip-tests
続いて生成されたsrc/app/shared/bottom-tabs/bottom-tabs.component.ts
に共通要素を実装していきます。TSファイル側では、利用したいアイコンや Ionic コンポーネントの登録などを行います。
import { Component } from '@angular/core';
import { RouterLink } from '@angular/router';
import {
IonTabBar,
IonTabButton,
IonIcon,
IonLabel
} from '@ionic/angular/standalone';
import { addIcons } from 'ionicons';
import {
gridOutline,
locationOutline,
colorPaletteOutline,
sparklesOutline,
informationCircleOutline
} from 'ionicons/icons';
@Component({
selector: 'app-bottom-tabs',
standalone: true,
imports: [
IonTabBar,
IonTabButton,
IonIcon,
IonLabel,
RouterLink // ナビゲーションに必須
],
templateUrl: './bottom-tabs.component.html',
styleUrl: './bottom-tabs.component.scss'
})
export class BottomTabsComponent {
constructor() {
// 使用するアイコンを登録
addIcons({
'grid-outline': gridOutline,
'location-outline': locationOutline,
'color-palette-outline': colorPaletteOutline,
'sparkles-outline': sparklesOutline,
'information-circle-outline': informationCircleOutline
});
}
}
続いてsrc/app/shared/bottom-tabs/bottom-tabs.component.html
にて、共通化したい要素のHTMLを実装します。
<ion-tab-bar slot="bottom">
<ion-tab-button tab="dashboard" [routerLink]="['/forecasts/dashboard']">
<ion-icon aria-hidden="true" name="grid-outline"></ion-icon>
<ion-label>ダッシュボード</ion-label>
</ion-tab-button>
<ion-tab-button tab="area" [routerLink]="['/forecasts/area']">
<ion-icon aria-hidden="true" name="location-outline"></ion-icon>
<ion-label>地域予報</ion-label>
</ion-tab-button>
<ion-tab-button tab="rainbow" [routerLink]="['/forecasts/rainbow']">
<ion-icon aria-hidden="true" name="color-palette-outline"></ion-icon>
<ion-label>虹予報</ion-label>
</ion-tab-button>
<ion-tab-button tab="aurora" [routerLink]="['/forecasts/aurora']">
<ion-icon aria-hidden="true" name="sparkles-outline"></ion-icon>
<ion-label>オーロラ予報</ion-label>
</ion-tab-button>
<ion-tab-button tab="introduction" [routerLink]="['/forecasts/introduction']">
<ion-icon aria-hidden="true" name="information-circle-outline"></ion-icon>
<ion-label>アプリ紹介</ion-label>
</ion-tab-button>
</ion-tab-bar>
共通化するコンポーネントができたので、各ページのコンポーネントでインポートしましょう。
// 例:weather-forecast.page.ts
import { BottomTabsComponent } from '../shared/bottom-tabs/bottom-tabs.component';
@Component({
selector: 'app-weather-forecast',
standalone: true,
imports: [
// 他のインポート...
BottomTabsComponent
],
// ...
})
export class WeatherForecastPage {
// ...
}
その後、.html
ファイル側の実装も置き換えます。
<!-- weather-forecast.page.html -->
<ion-content>
<!-- ページコンテンツ -->
</ion-content>
<app-bottom-tabs></app-bottom-tabs>
まとめ
Ionic + Angular の standalone コンポーネント機能を活用することで、効率的で保守性の高い共有ナビゲーションコンポーネントを実装できました。Angularはまだ AI にかなり支えてもらいながら使っている状態ですが、共通化などに慣れることで、アプリ開発への投入も進めていきたいなと思います。