mikeneko

View

Viewは、各画面表示にて前後の処理内容を設置するための機能です。
主に、画面表示の前後に実行されるハンドラの設定、 画面上のタグの操作(仮想DOMを使った操作)、 使用するテンプレートの設定を行います。

同じ動きをするクラスとしてControllerがありますが、
違いとしては1つのControllerに対してpublicメソッドを複数設置することで、 複数画面を一度に管理することができる点があるのに対して
Viewは1つのViewクラスに対して単一の画面しか管理することができません。

但し複数画面を1つのViewで操作できない代わりに、
構造が単純化されているためコードの管理がしやすくなります。

# 基本的な実装

例えば、src/app/config/App.tsの静的変数routesにて下記のルートがあるとした場合

"/page1": "page1",

src/app/view/Page1View.ts ファイルに次のコードを記述します。

import { View } from "View";

export class Page1View extends View {

    public handle(){

        console.log("page1 .... ok");
    }
}

Page1Viewは必ずViewの派生クラスとします。

これにより「/page1」にアクセスまたはそれに該当する画面に遷移したときは、 上記のPage1Viewクラスのhandleがメインのハンドラとして実行され、   コンソール上にpage1 .... okが表示されます。

この画面にV属性がbuttonのボタンを用意した場合、
それを押すとbutton click!を表示させるには下記のように
コード記述を変更します。

import { View } from "View";

export class Page1View extends View {

    public handle(){

        this.vdios.button.onClick = () => {
            alert("button click!");
        };
    }
}

このようにして各画面ごとに指定されているViewファイルを作成し、
それらの画面表示時の挙動を記述していきます。

# Viewのライフサイクル

基本的にViewのメインのハンドラはhandleですが、
それ以外のViewのライフサイクルは下記のとおりです。

{ 指定Viewへのルーティングが確定した場合 }
        |
View.handleBefore
        |
View.handleAfter
        |
{ レンダリング実行により画面切替 }
        |
        |
        |       templateが指定/変更された場合
        |----------------------------------- View.handleTemplateChanged
        |
        |
        |       headが指定/変更された場合
        |----------------------------------- View.handleHeadChanged
        |
        |
        |       headerが指定/変更された場合
        |----------------------------------- View.handleHeaderChanged
        |
        |
        |       footerが指定/変更された場合
        |----------------------------------- View.handleFooterChanged
        |
        |
        |
View.handleRenderBefore を実行
        |
View.handle を実行
        |
        |       前画面から進んでいる場合
        |----------------------------------- View.handleNext
        |
        | 
        |       前画面から戻っている場合
        |----------------------------------- View.handleBack
        |
        |
View.handleRenderAfter
        |
     ........
        |
{ 他のViewまたはControllerに移動が確定した場合 }
        |
View.handleLeave
        |
        |
        |       前画面から進んでいる場合
        |----------------------------------- View.handleLeaveNext
        |
        |
        |      前画面から戻っている場合
        |----------------------------------- View.handleLeaveBack
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |
    |       stackOpenを使って一時表示後に前画面に戻った場合
    |--------------------------------------------------------- view.handleLeaveStackClose

各ハンドラの解説を下記に示します。

- handleBefore / handleAfter イベント

指定Viewへのルーティングが確定した場合に一番最初に実行されるハンドラです。
この時点では画面切替がまだ行われていないので動的なテキスト挿入などの仮想DOM操作などには注意が必要です。

import { View } from "View";

export class Page1View extends View {

    public handle() {
        console.log("handle .... OK");
    }

    public handleBefore(){
        console.log("handle Before ..... OK");
    }
}

- handleTemplateChanged イベント

public変数templateにて、指定テンプレート名が変更された場合にのみ実行されるハンドラです。
使用方法についてはこちらで解説しています。;

引数にテンプレート内のUIクラスオブジェクトが渡されるため、
下記のように仮想VOMを直接操作することも可能です。

import { View } from "View";

export class Page1View extends View {

    public head : string = "head";

    public handle() {
        console.log("handle .... OK");
    }

    public handleTemplateChanged(template : UI) {
        template.vdios.title.text = "Page Title Text...";
    }
}

- handleHeadChanged イベント

public変数headにて、指定head名(実際はheadタグに使用するUI)が変更された場合にのみ実行されるハンドラです。
(headについてはこちらで解説)

引数にheadタグのUIクラスオブジェクトが渡されるため、
下記のようにheadタグ内の仮想VOMを直接操作することも可能です。

import { View } from "View";

export class Page1View extends View {

    public head : string = "head";

    public handle() {
        console.log("handle .... OK");
    }

    public handleHeadChanged(head : UI) {
        head.vdios.title.text = "Page Title Text...";
    }
}

- handleHeaderChanged イベント

public変数headerにて、指定header名(実際はheaderタグに使用するUI)が変更された場合にのみ実行されるハンドラです。
(headerについてはこちらで解説)

引数にheaderタグのUIクラスオブジェクトが渡されるため、
下記のようにheaderタグ内の仮想VOMを直接操作することも可能です。

import { View } from "View";

export class Page1View extends View {

    public head : string = "head";

    public handle() {
        console.log("handle .... OK");
    }

    public handleHeaderChanged(header : UI) {
        header.vdios.title.text = "Page Title Text...";
    }
}

- handleFooterChanged イベント

public変数footerにて、指定footer名(実際はfooterタグに使用するUI)が変更された場合にのみ実行されるハンドラです。
(footerについてはこちらで解説)

引数にfooterタグのUIクラスオブジェクトが渡されるため、
下記のようにfooterタグ内の仮想VOMを直接操作することも可能です。

import { View } from "View";

export class Page1View extends View {

    public head : string = "head";

    public handle() {
        console.log("handle .... OK");
    }

    public handlefooterChanged(footer : UI) {
        footer.vdios.title.text = "Page Title Text...";
    }
}

- handleRenderBefore イベント

画面切替が完了した直後に実行されるハンドラです。

handleとライフサイクルとしての位置は同じですが
こちらは複数のViewで継承元としている共通Viewにて
共通実行させたい内容がある場合にのみ使用してください。

- handle イベント

画面切替が完了した直後に実行されるハンドラです。
これがメインのハンドラとなるため、迷いがない場合はこちらを優先的に使用します。

前画面からの操作関係(進む・戻る)が関連する場合、処理の切り分けを行う場合は
handleNextまたはhandleBackを使う方法もあります。

- handleNext イベント

画面切替が完了した直後で、前画面から進んだ場合にのみ実行されるハンドラです。

- handleBack イベント

画面切替が完了した直後で、前画面から戻った場合にのみ実行されるハンドラです。

- handleRenderAfter イベント

画面切替が完了し、かつhandleイベントも終了後に実行されるハンドラです。

- handleLeave イベント

他のViewまたはControllerに画面移動が確定した直後に実行されるハンドラです。

特定の処理を画面表示中にのみ実施して、それを破棄・または終了させる場合は
このハンドラ上で指定してください。

例えば下記のように一定時間間隔でカウントアップしている処理などは、
このイベント上で停止させる必要があります。

import { VIew } from "View";

export class Page1View extends View {

    private interval;

    public handle() {

        // 定期実行を開始
        this.interval = setInterval(()=>{
            console.log("interval .... !");
        }, 1000);

    }

    // 画面から離れる場合
    public handleLeave() {
        // 定期実行を停止
        clearInterval(this.interval);
    }

}

なお画面から離れる際は他画面から戻る・進むに関係なくこのハンドラは実行されます。
戻る・進むごとに判別して処理を実装を切り分けたい場合は
Response.isBackResponse.isNextを使う、
あるいはhandleLeaveNextイベントhandleLeaveBackイベントを使用する方法があります。

- handleLeaveNextイベント

他のViewまたはControllerに画面移動が確定し、
かつ前画面から進んでいる場合にのみ実行されるハンドラです。

import { VIew } from "View";

export class Page1View extends View {

    private interval;

    public handle() {

    }

    // 前画面から進んだ場合
    public handleLeaveNext() {
        console.log("handle leave next ....");
    }
}

- handleLeaveBackイベント

他のViewまたはControllerに画面移動が確定し、
かつ前画面から戻ってきた場合にのみ実行されるハンドラです。

import { VIew } from "View";

export class Page1View extends View {

    private interval;

    public handle() {

    }

    // 前画面から戻ってきた場合
    public handleLeaveBack() {
        console.log("handle leave back ....");
    }
}

- handleLeaveStackClose イベント

このイベントはstackOpenメソッドを使って一時的に再前面に画面表示後に前画面に戻ろうとした際に実行されます。
stackOpenについてはこちらを参照

戻り値を指定すると、stackOpenメソッドの戻り値として値を渡すことができます。

import { VIew } from "View";

export class TimerSetView extends View {

    private interval;

    public handle() {

    }

    // handleLeaveStackClose
    public handleLeaveStackClose() {

        // 入力値を戻り値とする
        return this.vdos.timer.value;
    }
}

# 仮想DOM操作

レンダリングHTMLにて指定の要素に対してテキストの表示、及び押した際のイベントハンドラの実装等を行うには
仮想DOMを使って操作を行うのが便利です。
Viewでの仮想DOMはViewが表示または非表示されるごとに自動的に仮想DOMの取得作成・破棄が行われます。

仮想DOM(VirtualDom)についての詳細はこちらで解説しています

例としてある画面にてボタンを押した時の挙動を実装した例を下記に示しています。
まずレンダリングHTMLにてv属性(仮想DOM名)を指定したボタンのタグを設置します。

<a v="testButton">Button</a>

あとはViewクラスのハンドラにて指定の仮想DOMを押した時のイベントハンドラを設置するだけです。
this.vdiosにPage1Viewにて取得された仮想DOMリスト(VirtualDomクラス)が格納されているので
レンダリングHTMLにて指定した仮想DOM名をチェーンで指定します。

import { VIew } from "View";

export class Page1View extends View {

    public handle() {

        this.vdios.testButton.onClick = () => {
            // buttonが押されたときのイベント
            console.log("Button Click .... OK");
        };
    }
}

なお仮想DOMは上記vdiosvdosでも同様に記述ができます。

import { VIew } from "View";

export class Page1View extends View {

    public handle() {

        this.vdos.testButton.onClick = () => {
            // buttonが押されたときのイベント
            console.log("Button Click .... OK");
        };
    }
}

# sendData

# beginStatus

# view

# テンプレートの指定

Viewでは各画面で共通で使用する使用するテンプレートを指定することができます。
public変数templateにて使用するテンプレート名を指定します。

import { View } from "View";

export class Page1View extends View {

    public template : string = "default";

    public handle() {
        console.log("handle .... OK");
    }
}

テンプレートを使用しない場合はnullを記述してください。

import { View } from "View";

export class Page1View extends View {

    public template : string = null;

    public handle() {
        console.log("handle .... OK");
    }
}

テンプレートについてはこちらで詳しく解説しています

# head : string;

Viewではheadタグ内に挿入するUIを指定することができます。
UIについてはこちらで解説。

まず挿入するheadタグHTMLをsrc/app/ui/head.htmlに下記内容で準備します。

<meta charset="utf-8">
<title v-child="title"></title>

public変数headにてheadタグに挿入するUIを指定します。
(上記の場合はheadで指定。)

import { View } from "View";

export class Page1View extends View {

    public head : string = "head";

    public handle() {
        console.log("handle .... OK");
    }
}

headタグに何もUIを使用しない場合はnullを記述してください。

import { View } from "View";

export class Page1View extends View {

    public head : string = null;

    public handle() {
        console.log("handle .... OK");
    }
}

handleHeadChangedメソッドを使用することで、headタグ内が変更された際に実行されるハンドラを指定できます。
引数にheadタグのUIクラスオブジェクトが渡されるため、
例えば下記のように仮想VOMを使ってtitleタグの内容を変更することもできます。

import { View } from "View";

export class Page1View extends View {

    public head : string = "head";

    public handle() {
        console.log("handle .... OK");
    }

    public handleHeadChanged(head : UI) {
        head.vdios.title.text = "Page Title Text...";
    }
}

# header : string;

Viewではheaerdタグ内に挿入するUIを指定することができます。
UIについてはこちらで解説。

public変数headerにてheadタグに挿入するUIを指定します。

import { View } from "View";

export class Page1View extends View {

    public header : string = "header";

    public handle() {
        console.log("handle .... OK");
    }
}

headerタグに何もUIを使用しない場合はnullを記述してください。

import { View } from "View";

export class Page1View extends View {

    public header : string = null;

    public handle() {
        console.log("handle .... OK");
    }
}

Viewではfooterタグ内に挿入するUIを指定することができます。
UIについてはこちらで解説。

public変数footerにてfooterタグに挿入するUIを指定します。

import { View } from "View";

export class Page1View extends View {

    public footer : string = "footer";

    public handle() {
        console.log("handle .... OK");
    }
}

footerタグに何もUIを使用しない場合はnullを記述してください。

import { View } from "View";

export class Page1View extends View {

    public footer : string = null;

    public handle() {
        console.log("handle .... OK");
    }
}

# 一時的な画面表示 (stackOpen)

const value = await TimerSetView.stackOpen();
console.log(value);

TimerSetView.ts

import { VIew } from "View";

export class TimerSetView extends View {

    private interval;

    public handle() {

    }

    // handleLeaveStackClose
    public handleLeaveStackClose() {

        // 入力値を戻り値とする
        return this.vdos.timer.value;
    }
}