SvelteとIonicで始めるモバイルアプリケーション開発入門 Part3. ナビゲーション編
ion-navを使ったナビゲーションの実装
はじめに
この記事は前回の記事の続きとなります。
前回の記事では、Ionic Framework(以下、Ionic)のComponentを使って、モバイルアプリの基本的なレイアウトを実装しました。
今回は、同じくIonicのComponentを使って、皆様が慣れ親しんだ、ネイティブアプリの画面遷移を実装していきたいと思います。
ion-navを使った画面遷移
ion-navとは
ion-navは、画面に表示されるページをスタック形式で管理し、シームレスな画面遷移の制御を行うことができるComponentです。
画面遷移時にDOM全体を再描画するのではなく、ion-nav内に遷移後のページを追加(push)していくため、前の画面に戻る(pop)際に、最上部の画面だけが閉じられ、それまで表示していた画面がそのまま再利用される形で表示されます。
以下の画像は、公式ドキュメントの実装例です。
ネイティブアプリで画面遷移した時のような動きを再現していますね。
また、ion-navの、DOMの構造を見てみると、以下の画像のようになっています。
ion-navの中に、ion-pageというclassのついたdivタグが複数作られていますが、これがpushされたページのコンテナとなっています。
それぞれのion-pageが、値の異なるz-indexによって、別階層のレイヤーとして扱われていることがわかります。
また、ion-page-hiddenやcan-go-backといったclassが付与されていますが、これらのclassによって、ページや戻るボタン(ion-back-button)の表示/非表示が制御されるようになっています。
ion-navを使うモチベーション
モダンなフロントエンドフレームワークを利用している場合、標準のルーティングモジュールを使えば、SPAとして、サクサク動くアプリケーションを実装できます。実装コストも低いですし、Webアプリケーションとしてリリースするなら十分かもしれません。
ただし、モバイルアプリとしてリリースする場合、ネイティブのUIエンジンを使って実装されているアプリと比較すると、操作性は圧倒的に下がり、ユーザが感じるストレスは大きくなるでしょう。
ion-navを使うことで、iOS、Androidのビューコントロールを忠実に再現することができ、ネイティブアプリと遜色のないユーザ体験を生み出すことができます。
少し手間はかかるかもしれませんが、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-navのpopメソッドを使うことで、前のページに戻ることができます。他にもさまざまなプロパティやメソッドが定義されているので、詳しくは、Ionicの公式ドキュメントをご確認ください。
SvelteのComponentをHTMLElementに変換する
以下のように、SvelteのComponentをHTMLElementに変換する関数を作成します。
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
}
上記の関数に、SvelteのComponentを渡すことで、HTMLElementに変換できます。propsに引数を渡すことで、Componentのプロパティも設定できます。
他にも、SvelteのComponentをWeb Component化するなど、いくつかの方法が考えられますが、個人的にはこの方法が1番シンプルで簡単なのではないかと思います。
他のフロントエンドのフレームワークを使っている場合でも、ComponentをHTMLElement化さえしてしまえば、同じように実装することができるかと思います。
ion-navの初期化、画面遷移
先ほど作った関数を使って、以下のように、ion-navのrootを初期化できます。
<!-- 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-navのpopメソッドを使います。
<!-- 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内のコンテンツ描画領域のみを遷移の対象にできます。
まとめ
今回は、Ionicのルーティングモジュールである、ion-navについて紹介しました。Ionic Coreのion-navを使った実装例は、インターネットで調べても実装サンプルや情報が少なく、少しキャッチアップし辛いところはありますが、使ってみるととてもシンプルで便利なものだとわかりました。
Part1、Part2、本記事の内容を読めば、Svelte × Ionicを使って、ひとまず必要最低限の機能を持ったモバイルアプリを開発できるようになるのではないでしょうか。
今回は紹介しきれませんでしたが、他にも、ion-modalやion-refresherなど、Ionicの便利なComponentはたくさんあります。興味のある方は、ドキュメントを読みながら開発してみてはいかがでしょうか。
関連記事リンク
We are hiring!
本記事をご覧いただき、ネクストビートの技術や組織についてもっと話を聞いてみたいと思われた方、カジュアルにお話しませんか?
・今後のキャリアについて悩んでいる
・記事だけでなく、より詳しい内容について知りたい
・実際に働いている人の声を聴いてみたい
など、まだ転職を決められていない方でも、ネクストビートに少しでもご興味をお持ちいただけましたら、ぜひカジュアルにお話しましょう!
🔽申し込みはこちら
https://hrmos.co/pages/nextbeat/jobs/1000008
また、ネクストビートについてはこちらもご覧ください。