SvelteとIonicで始めるモバイルアプリケーション開発入門 Part3. ナビゲーション編

ion-navを使ったナビゲーションの実装

Junya Kawai
nextbeat-engineering
12 min readDec 27, 2023

--

はじめに

こんにちは、ネクストビートでエンジニアをしている川井です。

この記事は前回の記事の続きとなります。

前回の記事では、Ionic Framework(以下、Ionic)のComponentを使って、モバイルアプリの基本的なレイアウトを実装しました。

今回は、同じくIonicComponentを使って、皆様が慣れ親しんだ、ネイティブアプリの画面遷移を実装していきたいと思います。

ion-navを使った画面遷移

ion-navとは

ion-navは、画面に表示されるページをスタック形式で管理し、シームレスな画面遷移の制御を行うことができるComponentです。

画面遷移時にDOM全体を再描画するのではなく、ion-nav内に遷移後のページを追加(push)していくため、前の画面に戻る(pop)際に、最上部の画面だけが閉じられ、それまで表示していた画面がそのまま再利用される形で表示されます。

以下の画像は、公式ドキュメントの実装例です。

ネイティブアプリで画面遷移した時のような動きを再現していますね。

https://ionicframework.com/docs/ja/api/nav

また、ion-navの、DOMの構造を見てみると、以下の画像のようになっています。

ion-navのDOMの構造

ion-navの中に、ion-pageというclassのついたdivタグが複数作られていますが、これがpushされたページのコンテナとなっています。

それぞれのion-pageが、値の異なるz-indexによって、別階層のレイヤーとして扱われていることがわかります。

また、ion-page-hiddencan-go-backといったclassが付与されていますが、これらのclassによって、ページや戻るボタン(ion-back-button)の表示/非表示が制御されるようになっています。

ion-navを使うモチベーション

モダンなフロントエンドフレームワークを利用している場合、標準のルーティングモジュールを使えば、SPAとして、サクサク動くアプリケーションを実装できます。実装コストも低いですし、Webアプリケーションとしてリリースするなら十分かもしれません。

ただし、モバイルアプリとしてリリースする場合、ネイティブのUIエンジンを使って実装されているアプリと比較すると、操作性は圧倒的に下がり、ユーザが感じるストレスは大きくなるでしょう。

ion-navを使うことで、iOSAndroidのビューコントロールを忠実に再現することができ、ネイティブアプリと遜色のないユーザ体験を生み出すことができます。

少し手間はかかるかもしれませんが、Ionicを使って、モバイルアプリを開発するなら、ion-navを使うことをオススメします。

実装方法

ion-navの基本

ここからは、実装方法について簡単に紹介します。

まずは、ion-appの中にion-navを記述します。

<ion-app>
<ion-nav root="component"></ion-nav>
</ion-app>

rootというパラメータには、最初に描画したいComponentを設定します。

rootの型定義は以下のようになっており、

Function | HTMLElement | ViewController | null | string | undefined

HTMLElementや、Web Componentの名前を文字列として設定することで、その要素をルートページとして表示できます。

また、ion-navにはpushというメソッドがあり、引数にComponentを渡すことで、画面遷移を実行します。受け取れる形式はrootとほぼ同じです。

逆に、ion-navpopメソッドを使うことで、前のページに戻ることができます。他にもさまざまなプロパティやメソッドが定義されているので、詳しくは、Ionicの公式ドキュメントをご確認ください。

SvelteのComponentをHTMLElementに変換する

以下のように、SvelteComponentHTMLElementに変換する関数を作成します。

import type { ComponentProps, ComponentType, SvelteComponent } from "svelte"

/** SvelteのComponentからHTMLElementを作成する */
export const createDOM = <T extends SvelteComponent>(
component: ComponentType<T>,
props?: ComponentProps<T>
): HTMLElement => {
const target = document.createElement('div')
new component({ target, props })
return target
}

上記の関数に、SvelteComponentを渡すことで、HTMLElementに変換できます。propsに引数を渡すことで、Componentのプロパティも設定できます。

他にも、SvelteComponentWeb Component化するなど、いくつかの方法が考えられますが、個人的にはこの方法が1番シンプルで簡単なのではないかと思います。

他のフロントエンドのフレームワークを使っている場合でも、ComponentHTMLElement化さえしてしまえば、同じように実装することができるかと思います。

ion-navの初期化、画面遷移

先ほど作った関数を使って、以下のように、ion-navrootを初期化できます。

<!-- Root.svelte-->
<script lang="ts">
import { createDOM } from "$lib/script/util"
import Page1 from "$pages/Page1.svelte";
</script>

<ion-app>
<ion-nav id="nav" root={createDOM(Page1)} />
</ion-app>

また、以下のように、画面遷移が実行できます。

<!-- Page1.svelte -->
<script lang="ts">
import { createDOM } from "$lib/script/util"
import Page2 from "$pages/Page2.svelte"

const move = () => {
const page2 = createDOM(Page2)
const nav = document.getElementById('nav').push(page2)
}
</script>

<ion-header />
<ion-content class="ion-padding">
<ion-button on:click={move}>
move to next page
</ion-button>
</ion-content>

前の画面に戻るには、ion-back-buttonを使うか、ion-navpopメソッドを使います。

<!-- Page2.svelte -->
<script lang="ts">
const back = () => {
const nav = document.getElementById('nav').pop()
}
</script>

<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button text="戻る"></ion-back-button>
</ion-buttons>
<ion-title>ページ2</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<ion-button on:click={back}>
back to previous page
</ion-button>
</ion-content>

ion-navは1つのアプリ内で複数利用することもできるため、IonNav.svelteのようなComponentを作っておくと、複数のion-navを一元管理できたり、どこからでも簡単に探せたりして便利です。

<!-- IonNav.svelte -->
<script lang="ts" context="module">
/**
* ナビゲーションのID一覧
* nav-app: アプリ全体のナビゲーション
* nav-home: ホームタブ内部のナビゲーション
* nav-search: 検索タブ内部のナビゲーション
* nav-fav: お気に入りタブ内部のナビゲーション
* nav-settings: 設定タブ内部のナビゲーション
*/
export const navIds = [
'nav-app',
'nav-home',
'nav-search',
'nav-fav',
'nav-settings',
] as const

/** idを指定してion-navを探す*/
export const findNavById = (id: typeof navIds[number]): HTMLIonNavElement => {
return document.getElementById(id) as HTMLIonNavElement
}
</script>

<script lang="ts">
/** IonNavを特定するためのID */
export let id: typeof navIds[number]

/** IonNavのルート要素 */
export let root: HTMLElement
</script>

<ion-nav {id} {root} />

ion-tabsを使っている場合、それぞれのtabの内部でion-navを使うことで、画面全体ではなく、tab内のコンテンツ描画領域のみを遷移の対象にできます。

複数のion-navを使った実装例

まとめ

今回は、Ionicのルーティングモジュールである、ion-navについて紹介しました。Ionic Coreion-navを使った実装例は、インターネットで調べても実装サンプルや情報が少なく、少しキャッチアップし辛いところはありますが、使ってみるととてもシンプルで便利なものだとわかりました。

Part1Part2、本記事の内容を読めば、Svelte × Ionicを使って、ひとまず必要最低限の機能を持ったモバイルアプリを開発できるようになるのではないでしょうか。

今回は紹介しきれませんでしたが、他にも、ion-modalion-refresherなど、Ionicの便利なComponentはたくさんあります。興味のある方は、ドキュメントを読みながら開発してみてはいかがでしょうか。

関連記事リンク

We are hiring!

本記事をご覧いただき、ネクストビートの技術や組織についてもっと話を聞いてみたいと思われた方、カジュアルにお話しませんか?

・今後のキャリアについて悩んでいる
・記事だけでなく、より詳しい内容について知りたい
・実際に働いている人の声を聴いてみたい

など、まだ転職を決められていない方でも、ネクストビートに少しでもご興味をお持ちいただけましたら、ぜひカジュアルにお話しましょう!

🔽申し込みはこちら
https://hrmos.co/pages/nextbeat/jobs/1000008

また、ネクストビートについてはこちらもご覧ください。

🔽エントランスブック
https://note.nextbeat.co.jp/n/nd6f64ba9b8dc

--

--