画面表示を切り替える

一般的なアプリケーションでは画面表示を切り替えたり、1つの画面内で複雑な画面構成を必要とすることが多々あります。ここでは Alier での基本的な画面の切り替え方法を学びましょう。

この節では、複数の画面を作り、ボタンで画面を切り替えられるアプリケーションを作成します。

画面を切り替える方法は2通りあります。どちらの切り替え方も確認できるアプリケーションにします。

  • アプリケーション画面全体を切り替える
  • 画面の一部分のみを切り替える

それではプログラムを見てみましょう。

ソースコード


 

  • /app_res/main.js
Object.assign(globalThis, await Alier.import("/alier_sys/AlierFramework.js"));
Object.assign(globalThis, await Alier.import("my_view_logic.js"));

async function main() {
    setupAlier();

    Alier.View.attach(new SwitchView());
}


  • /app_res/first.html
<html>
  <head>
  </head>
  <body>
    <alier-container id="main_container">
      First Page<br>
      <input type="button" id="forward" value="forward" data-ui-component data-active-events="click"/><br><br>
      <input type="button" id="switch" value="switch" data-ui-component data-active-events="click"/><br>
      <alier-view id="sub_view" data-ui-component style="border:2px solid; padding:10px; margin: 20px;">
        <alier-container id="sub_container">
          Sub View<br>
          <input type="text" id="text" value="text" data-ui-component /><br>
        </alier-container>
      </alier-view>
    </alier-container>
  </body>
</html>


  • /app_res/second.html
<html>
  <head></head>
  <body>
    <alier-container>
      Second Page<br>
      <input type="button" id="back" value="back" data-ui-component data-active-events="click"/>
    </alier-container>
  </body>
</html>


  • /app_res/my_view_logic.js
class SwitchView extends ViewLogic {
    sub_backup;

    constructor() {
        super();

        this.relateElements(
            this.collectElements(
                this.loadContainerSync({ file: "first.html", id: "main_container" })
            )
        );

        this.sub_view.attach(new SubView("This is A"));
        this.sub_backup = new SubView("This is B");
    }

    async messageHandler(msg) {
        return await msg.deliver({
            forward: msg => {
                Alier.View.attach(new SecondView());
            },

            switch: msg => {
                this.sub_backup = this.sub_view.attach(this.sub_backup);
            }
        });
    }
}

class SecondView extends ViewLogic {
    constructor() {
        super();

        this.relateElements(
            this.collectElements(
                this.loadContainerSync({ file: "second.html" })
            )
        );
    }

    async messageHandler(msg) {
        return await msg.deliver({
            back: msg => {
                Alier.View.attach(new SwitchView());
            }
        });
    }
}

class SubView extends ViewLogic {
    constructor(text) {
        super();

        this.relateElements(
            this.collectElements(
                this.loadContainerSync({ file: "first.html", id: "sub_container" })
            )
        );

        this.text.value = text;
    }
}

await Alier.export({ SwitchView });

以下は実行結果です。

起動画面

サンプル実行画像

forword ボタン押下

画面切り替え1

switch ボタン押下

画面切り替え2

解説

エントリーポイントの定義

Object.assign(globalThis, await Alier.import("/alier_sys/AlierFramework.js"));
Object.assign(globalThis, await Alier.import("my_view_logic.js"));

今回は ViewLogic の定義を、main.js から分離して view_logic.js を作りました。main() で参照できるようにここでインポートします。


async function main() {
    setupAlier();

    Alier.View.attach(new SwitchView());
}

main() で、トップ画面を Alier.View にアタッチします。ここでは先ほどインポートした ViewLogic クラス、SwitchView のインスタンスを生成して渡します。

表示コンテンツの定義

まず、アプリケーションの表示コンテンツを生成していきます。

<html>
  <head>
  </head>
  <body>
    <alier-container id="main_container">
      First Page<br>
      <input type="button" id="forward" value="forward" data-ui-component data-active-events="click"/><br><br>
      <input type="button" id="switch" value="switch" data-ui-component data-active-events="click"/><br>
      <alier-view id="sub_view" data-ui-component style="border:2px solid; padding:10px; margin: 20px;">
        <alier-container id="sub_container">
          Sub View<br>
          <input type="text" id="text" value="text" data-ui-component /><br>
        </alier-container>
      </alier-view>
    </alier-container>
  </body>
</html>

アプリケーション起動時に表示される トップ画面です。2類の画面切り替え用のボタンを設置しています。上のボタンがアプリケーション画面全体を切り替えるもの、下のボタンが画面の一部を切り替える機能のボタンです。

<alier-view> は Alier のカスタム要素で、画面の一部を切り替えるのに使用します。


<html>
  <head>
  </head>
  <body>
    <alier-container>
      Second Page<br>
      <input type="button" id="back" value="back" data-ui-component data-active-events="click"/>
    </alier-container>
  </body>
</html>

アプリケーション全体を切り替えた時に表示される画面です。ここでは トップ画面に戻るボタンを設置しています。

これで表示コンテンツの構成は決まりました。


ViewLogicの定義

class SwitchView extends ViewLogic {
    sub_backup;

    constructor() {
        super();

        this.relateElements(
            this.collectElements(
                this.loadContainerSync({ file: "first.html", id: "main_container" })
            )
        );

トップ画面となる SwitchView を定義します。

コンストラクタの中で loadContainerSync() を使用してコンテナの内容を HTML ファイルから読み込んでいます。

info

loadContainer() には非同期版と同期版が用意されています。非同期版で HTML ファイルを読み込む場合は、関数を呼んだ直後に読み込みが完了していない場合があり、そのタイミングで要素に操作を加えるには同期処理を記述する必要があります。そのような場合は同期版 loadContainerSync() の使用が便利です。

"file: " で設定しているのは読み込む HTML ファイル、"id: " で設定しているのは <alier-container> の id です。

このように設定することで、HTML ファイル内の指定された要素の id を抽出して読み込みます。


        this.sub_view.attach(new SubView("This is A"));

ここでは画面内の一部分である<alier-view> 要素に、別の ViewLogicattach() して表示を切り替えています。

<alier-view> で定義した要素は attach() することが可能なエレメントです。Alier.View も実体は <alier-view> エレメントで、アプリケーション起動時に最初から存在し、画面全体を覆うように設置されています。

この例のようにコンテナの中に <alier-view> を設置することで**コンテナをネストする***ことも可能です。

アクティビティ毎に適切にコンテナを作ることで、複雑な画面を構成することが出来ます。


        this.sub_backup = new SubView("This is B");
    }

画面を切り替える表示コンテンツをあらかじめ生成して格納しておきます。

同じクラスを生成していますが、識別するためにコンストラクタ引数に異なる文字列を渡しています。


画面切り替えを処理をする

    async messageHandler(msg) {
        return await msg.deliver({
            forward: msg => {
                Alier.View.attach(new SecondView());
            },

            switch: msg => {
                this.sub_backup = this.sub_view.attach(this.sub_backup);
            }
        });
    }
}

ボタンのイベントをハンドリングして画面を切り替える処理を行います。

forward ボタンでは、新たに生成した SecondViewAlier.Viewattach() しています。

これによって SwitchView から SecondView に画面が切り替わります。

一方、switch ボタンでは、sub_viewthis.sub_backup をアタッチしています。

attach() した際に、すでにアタッチされた ViewLogic があった場合は dettach() してそのインスタンスを attach() の返値として返します。

ここでは返ってきた ViewLogic を再び this.sub_backup に入れることで、ボタンを押すたびに、二つの ViewLogic が交互に入れ替わるよう実装しています。


class SecondView extends ViewLogic {
    constructor() {
        super();

        this.relateElements(
            this.collectElements(
                this.loadContainerSync({ file: "second.html" })
            )
        );
    }

    async messageHandler(msg) {
        return await msg.deliver({
            back: msg => {
                Alier.View.attach(new SwitchView());
            }
        });
    }
}

最後に、切り替え先のコンテナを定義します。

トップ画面の切り替えに使用する SecondView の定義です。ボタンを押されたら SwitchView に画面を戻る処理を実装しています。


class SubView extends ViewLogic {
    constructor(text) {
        super();

        this.relateElements(
            this.collectElements(
                this.loadContainerSync({ file: "first.html", id: "sub_container" })
            )
        );

        this.text.value = text;
    }
}

画面の一部分を切り替えるための SubView を定義します。コンストラクタの引数で受け取った文字列を表示に反映しています。


await Alier.export({ SwitchView });

最後に、トップ画面となる SwitchViewmain() 関数で使用するために、Alier.export()でエクスポートしておきます。エクスポートされた機能は Alier.import() で使用可能になります。


実行結果

サンプルを動かして画面切り替えをしてみましょう。

  1. forward ボタンを押下します。

    Second画面表示

    画面全体が切り替わりました。

  2. back ボタンを押下して トップ画面に戻ったら、次に switch ボタンを押下します。

    SubView切り替え

    表示していたテキストが「This is A」から「This is B」に変化しました。


画面切り替え時の値の保持

ところで、このサンプルでテキストを編集すると、切り替え時に値を保持する場合と初期化される場合がある事が気になった方がいるかもしれません。

それについて確認してみましょう。サンプルを最初の状態に戻して、今度はテキストの状態に注目して以下の操作を行ってください。

  1. 「This is A」をクリックしてテキストを「This is a pen」に書き換え

  2. switch ボタンを押下

  3. 「This is B」をクリックしてテキストを「This is an apple」に書き換え

  4. switch ボタン押下

    入力された値が表示される 入力された値が表示される2

テキスト表示が 「This is a pen」に変わったのを確認できたでしょうか? もう一度 switch を押下すれば、「This is an apple」が表示されるはずです。

それが確認出来たら続けて以下の操作を行ってみましょう。

  1. forward ボタンを押下

  2. back ボタンを押下

  3. テキスト表示を確認

    値が初期化される 値が初期化される2

テキスト表示が 「This is A」、「This is B」に初期化されたのが確認できたでしょうか。

switch のボタンの切り替えでは入力結果が保持されて、forward ボタンの切り替えでは保持されなかったのは何故でしょう?

画面切り替えを処理をする」で解説した通り、switch ボタンのイベントではコンストラクタであらかじめ生成した ViewLogic インスタンスを交互に切り替えるように処理しました。

切り替えられた時、ViewLogic インスタンスを保持すると関連付けた要素の値はそのまま残ります。保持したコンテナを再度アタッチすることで、切り替える直前の状態を保ったまま画面を戻す事が出来ます。

forward の切り替えでは、今まで表示していたコンテナは捨てられ新しく生成したインスタンスをアタッチしています。そのため入力は初期化されました。

コンテナを生成するタイミングの違いによってこのように差が生じるという事をサンプルで確認できました。

これを踏まえて、forward 側の画面切り替えでも値を保持するようにしてみましょう。

  • コンストラクタであらかじめインスタンスを生成し、変数に格納
  • 切り替える度に new で生成しなおしていたのを、変数に格納したインスタンス変えてアタッチする。

アタッチした際の返値をまた変数に入れておけば、何度切り替えても値を保ったままの画面を確認できるはずです。