MVVMの実装例
最終更新
最終更新
では実際にMVVMの仕組みを作ってみましょう。
サンプルは以前のFormのサンプルを元に、入力欄を増やしたものとなります。
HTMLを見てみると、入力欄を増やした分だけinput要素が増えています。それぞれ 固有の(重複しない)name, id属性 を指定しています。JSの方を見ていきます。
コード量はそれなりにありますが、いつものように上から順に見ていきます。
今回重要なのは独自の mount()
関数です。この関数はモデルとして扱う初期データ(オブジェクト)を引数として受け取り、生成されたモデルと unmount()
関数を返却しています。mountの中の処理を順に説明していきます。
引数のデータを元にProxy(※)のインスタンス(以降、モデルと呼ぶ)を生成する。Proxyのコンストラクタの第二引数に渡した set()
関数はsetterとして扱われる(= モデルのプロパティに値を代入した時に呼び出される) ※ Proxyはブラウザ標準のAPIですが、IE11では動かないので案件で利用する場合は注意してください。
set()
関数の中では、変更のあったプロパティ名(キー)と関連するinput要素を取得する。関連する要素が存在した場合のみ、その要素の値を更新する。(= モデルからビューへの反映)
for (const prop in data) {...}
の部分ではデータの各キー毎に、関連するinput要素を取得する。要素が存在したらinput要素のinput(キーボード入力)イベントにイベントハンドラをセットする。そのイベントハンドラ内ではキーボード入力された最新の入力値を、モデルにセットする。(= ビューからモデルへの反映)
戻り値として生成されたモデルと unmount()
関数を返却する。
先程の mount()
関数は、 $(() => {...})
の中で呼び出されています。これは $(document).ready(...)
と同じ意味で、HTML内にある要素がすべて描画されたタイミング(= DOMContentLoaded / DOM Readyとも呼ぶ)で引数に渡した関数を実行する。という意味になります。
JavaScriptはHTML内にある要素の描画後に呼び出されるとは限らないので、こういったHTML内の要素の描画を待ってから実行する書き方 をすることがあります。これはReactやVue.jsなどでも良く使われる書き方です。 $(document).ready(...)
はjQueryのAPIですが、ブラウザの標準APIで言い換えるとこういう書き方になります。
$(document).ready(...)
の中に書く(= DOMContentLoadedイベントのハンドラとして登録する)ことで、HTML内の要素の描画を待つ。
描画されたら、 mount()
関数を呼び出してモデルを取得する。
id="random"
なボタンを押した時に、モデルのそれぞれのプロパティ(name/firstFriendName/secondFriendName)をランダムな値( getRandomName()
の戻り値 )で更新する。プロパティの更新時にモデルによって自動でHTML(ビュー/UI)への変更後の値の反映(描画)が行われる。
フォームの送信(submit)イベントのイベントハンドラの中で、モデルの値を引数としてAJAXを使ってAPIにリクエストを送信する。
以前のサンプルと同様にAPIからのレスポンスを画面に描画する。
以上がMVVMに準拠した実装のサンプルとなります。コードが長く感じたかもしれませんが mount()
関数の部分はライブラリ(= 再利用するもの)として使えるので、一度書いてしまえば、かんたんに複雑な入力フォームを作る事が可能となります。
ただ今回の mount()
関数は基本的な仕様しか実装出来てないので、input要素がちゃんと存在するかのチェック(エラーチェック)や、クロスブラウザでの動作検証などを経た上で商用レベル(開発案件で使えるレベル)にはならないかなとは思います。(= そのままではお仕事には使えません)
なので、実際の案件ではこういう機能を自前で書かずに React/Vue.js/Angular といった既存のライブラリ(/ フレームワーク)を使うことで同等の機能を実現する事が多いです。とはいえ内部的にどういった事が行われているのかを正しく理解しておくと、デバッグやトラブルシューティングの際に役に立つので、是非理解しておきましょう!