mithril.jsを試してみた

はじめに

groongaのgoバインディングでWikipedia全文検索のサンプルウェブアプリを作ってみた · hnakamur's blog at githubのフロントエンドをMithrilで書いてみました。

参考にした記事

mithril.jsについてはまず以下の記事

を読み、その後本家のGuideの左のリンクから辿れる記事とLearn Mithrilの記事をひと通り読みました。

今回は試していませんが、 Velocity.js animations in Mithrilの記事で、Velocity.jsを組み合わせてアニメーションを実現する方法も紹介されていました。

データバインディングの仕組み

mithril.jsを読み込むと m というグローバル変数にmithrilのモジュールが定義されます。モジュールと言ってもビューの関数としても使いますし、他の関数の名前空間としても使っています。

まずモデルの定義ですが、Getting StartedModelのところにあるように、m.propを使って

プロパティ = m.prop(初期値)

と書くことで、プロパティが作られます。プロパティは値ではなくてgetter-setterの関数になっていて、 プロパティ() で値を取得、 プロパティ(値) で値を設定します。

モデル層はドメインモデルに限定して、UIの状態はView-Modelとして定義します。

Controllerはビューモデルを保持し、ビューでのイベントハンドラやビューを操作する関数を定義します。

HTMLの構造はViewの例にあるように、 m という関数を使って記述します。JavaScriptで書くのですが宣言的に書けるので、見やすいです。

  • 第一引数にCSSクエリ文字列を書くと、そのタグ名や属性を持った要素が作られます。
  • 第二引数は省略可能ですが、属性のハッシュを指定できます。
  • 最後の引数で子要素を指定します。複数の場合は配列、単一の子要素なら m の呼び出し、テキスト要素なら文字列を指定します。

あとはm.mountm.componentでマウントすると、モデルの値が変わったらビューの表示もmithrilが更新してくれます。

今回作成したソース

基本的な構造はComponentsClassic MVCのパターンを真似しました。

ソースはcgoroonga/index.htmlにあります。お手軽に試していたレベルなのでstyleタグやscriptタグもhtml内に書いちゃってます。

コンポーネントの階層は以下のようになっています。

  • SearchWidget: 検索画面全体のウィジェット
    • SearchForm: 検索フォーム
      • SelectWidget: ドロップダウンウィジェット(検索期間選択用)
    • SearchResultWidget: 検索結果表示ウィジェット
    • PaginationWidget: ページネーションウィジェット

検索フォームをサブミットした時とページネーションのリンクをクリックした時は、 The observer patternObservable 経由で検索処理を実行しています。

一方、検索期間のSelectWidgetの選択を切り替えた時は、SelectWidgetのコントローラの onchange →SelectWidgetのビューモデルの onchange →SearchWidgetのコントローラの onchangetimespan と呼び出しを連鎖して検索処理を実行するようにしてみました。

ビューの定義時に m.component でサブコンポーネントを埋め込むときに引数でビューモデルやイベントハンドラを渡しておいて、ビューではそのビューモデルを参照し、イベントが起きたら引数で渡されていたイベントハンドラを呼び出すというパターンです。

おわりに

mithril.jsを使うとコンポーネントごとにMVCパターンで実装できて、コンポーネント間はObservableで連携するか、ビューでサブコンポーネントを利用する際に引数で渡したビューモデルとイベントハンドラで連携することが出来、見通しが良いと感じました。

mithril.jsのソースも現時点で1161行とコンパクトなのも魅力です。まだバージョン v0.2.0 ですが、今後が楽しみなフレームワークですね。