m.route
ラウティング(Routing = アメリカ英語読みはルーティングよりもラウティングが近い)は、シングルページアプリケーション(SPA)を作るための仕組みです。他のページに行く時に、フルにブラウザをリフレッシュしなくても済むアプリケーションを実現することができます。
この機能を使うと、各ページをブックマークしたり、ブラウザの履歴の機能はそのままに、シームレスなナビゲーションが可能になります。
このメソッドは4つの異なる機能をオーバーロードしています:
m.route(rootElement, defaultRoute, routes)- アプリケーションで使用できるURLとその時にロードされるコンポーネントの定義m.route(path)- 他のラウトへリダイレクトm.route()- 現在アクティブなラウトの取得m.route(element)- ラウトのモードを抽象化し、現在のモードで利用可能なエレメントの実リンクを取得
ラウトはシングルページアプリケーション(SPA)を実現しやすくする仕組みで、 location.hash、HTML5のURL書き換え、location.querystringのどれかの方法を使って実装できます。それぞれの実装方法の詳細については、m.route.modeを参照してください。
ラウトの定義
使用方法
ラウトを定義する時は、ホストとなるDOM要素と、デフォルトのラウト、あとは遷移する可能性のあるラウトとそれをレンダリングするためのコンポーネントのキー・バリューのマップが必要となります。ラウトのリストを定義した場合は、モジュールの初期化をするためにm.mountを呼ぶ必要はありません。m.routeが代わりに呼んでくれます。
次のサンプルは、<body>のレンダリングをする、3つのラウトを定義しています。home、login、dashboardはそれぞれコンポーネントです。どのようにコンポーネントを定義するか見ていきましょう。
m.route(document.body, "/", {
"/": Home,
"/login": Login,
"/dashboard": Dashboard,
});
:を前に付いた単語を書くことで、ラウトに引数を設定することができます。
次のサンプルはuserIDパラメータを取るラウトです。
//サンプルコンポーネント
var Dashboard = {
controller: function() {
return {id: m.route.param("userID")}
},
view: function(controller) {
return m("div", controller.id);
}
}
//#記号から始まるラウトを使用するための設定
m.route.mode = "hash";
//ラウトの定義
m.route(document.body, "/dashboard/johndoe", {
"/dashboard/:userID": Dashboard
});
これを実行すると、http://server/#/dashboard/johndoeにリダイレクトして、下記のタグを挿入します:
<body><div>johndoe</div></body>
上記のサンプルのdashboardはコンポーネントです。モジュールはcontrollerプロパティとviewプロパティを持ちます。URLがラウトにマッチすると、対応するコンポーネントのコントローラがインスタンス化されて、引数としてビューに渡されます。
この場合、ひとつのラウトしかないため、アプリケーションはデフォルトのラウトの"/dashboard/johndoe"にリダイレクトされます。。
johndoeという文字列が:userIDパラメータに結び付けられます。このパラメータは、コントローラ内でm.route.param("userID")というAPI呼び出しをするとプログラムから参照できます。
m.route.modeは、URLのどの部分をラウトとして使うかを設定します。
可変個引数のラウト
省略記号(...)をラウトの引数の名前に付けると、スラッシュを含むURLにマッチさせることができます:
m.route(document.body, "/files/pictures/pic1.jpg", {
"/files/:file...": gallery
});
m.route.param("file") === "pictures/pic1.jpg"
m.route(document.body, "/blog/2014/01/20/articles", {
"/blog/:date.../articles": articleList
});
m.route.param("date") === "2014/01/20"
Mithrilはラウトのマッチを定義された順番に行っていきます。そのため、可変個の引数を持つラウトは末尾に書かないと、より範囲の狭いラウトのマッチが行われなくなります。
m.route(document.body, "/blog/archive/2014", {
"/blog/:date...": Component1, //上記のデフォルトパスはこのラウトに先にマッチします!
"/blog/archive/:year": Component2
});
m.route.param("date") === "archive/2014"
//`m.route.param("year") == "2014"`が成立するように、ラウト定義の順番を変えること
ラウトとクエリー文字列
ラウトパラメータ以外にも、クエリー文字列を使って任意のデータをm.route.paramに渡すことができます。
m.route("/grid?sortby=date&dir=desc")
var sortBy = m.route.param("sortby") // "date"
var dir = m.route.param("dir") // "desc"
ラウト変更時に後処理コードを実行する
コンポーネントのコントローラがonunloadインスタンスメソッドを定義している場合、ラウトが変更されるとこのメソッドが呼び出されます。
var Home = {
controller: function() {
return {
onunload: function() {
console.log("ホームをアンロード");
}
};
},
view: function() {
return m("div", "Home")
}
};
var Dashboard = {
controller: function() {},
view: function() {}
};
//デフォルトラウト(home)に移動
m.route(document.body, "/", {
"/": Home,
"/dashboard": Dashboard,
});
//re-route to dashboard
m.route("/dashboard"); // logs "unloading home component"
This mechanism is useful to clear timers and unsubscribe event handlers. コンポーネントが階層化されている場合は、階層の中のモジュールのすべてのonunloadを呼ぶこともできますし、特定のコンポーネントをアンロードするときにはpubsubライブラリを呼ぶこともできます。
シグニチャ
void route(DOMElement rootElement, String defaultRoute, Object<Component> routes) { String mode, String param(String key), String buildQueryString(Object data), Object parseQueryString(String data) }
where:
Component :: Object { void controller(), void view(Object controllerInstance) }
DOMElement root
ビューのテンプレートの結果が作成されるDOMエレメント。
String defaultRoute
現在のURLが、どの定義されたラウトにもマッチしなかった時にリダイレクトされラウト
Object
routes 利用可能なラウトと、そのラウトに対応するコンポーネントの対応が格納されたキー・バリュー・マップ。キーは絶対パスを指定しますが、動的パラメータを含めることができます。動的パラメータはコロン(
:)で始まっている単語です。{'/path/to/page/': pageComponent}- 基本パス名のラウト{'/path/to/page/:id': pageComponent}-idと呼ばれる動的パラメータを含むパス名のラウトこのラウとは、/path/to/page/1、/path/to/page/testといったURLが指定された場合に選択されます。{'/user/:userId/book/:bookId': userBookComponent}- 2つのパラメータを含むパス名のラウト動的パラメータは、URLパターンに応じてコンポーネント選択する時に使用できるワイルドカードです。URLの中で動的パラメータを置き換えた値は、
m.route.param()を通じて取得することができます。ラウトの解決に使うURLの部位は、
m.route.modeによって決定されます。デフォルトではラウト集に対してクエリー文字列がURLの構成要素として解釈されます。現在のページのURLが、設定されたラウトにマッチした場合には、対応するコンポーネントがアクティブになります。コンポーネントに関しては
m.componentを参照してください。-
m.route.mode
String mode
m.route.modeプロパティを使うと、どのURLに対してラウティングの仕組みを実装するかを定義できます。このプロパティには、"search"、"hash"、"pathname"のいづれかの文字列を設定できます。デフォルトは"search"です。この設定を変更する場合には、m.routeを呼び出す前に行ってください。searchモードはクエリー文字列 (?以降)を利用します。このモードを使うと、名前付きのアンカー(例えば、<a href="#top">トップに戻る</a>、<a name="top"></a>)を使うことができますが、IE8の場合はhistory.pushStateのサポートがないため、ページリフレッシュが発生してしまいます。サンプルURL:
http://server/?/path/to/pagehashモードはハッシュ(#以降)を使います。このモードは唯一、どのブラウザでもページリフレッシュが発生しません。しかし、このモードでは名前付きアンカーが使えなくなります。サンプルURL:
http://server/#/path/to/pagepathnameモードは特別な文字を含まないURLを許可します。しかし、このモードでブックマークとページリフレッシュをサポートするためには、サーバ側にも手を加える必要があります。IE8上では、常にページリフレッシュが発生します。サンプルURL:
http://server/path/to/pagepathnameモードを使用するためのサーバ設定の中で、一番簡単な方法は、どのURLが要求されても同じコンテンツを返すようにする方法です。Apacheを使っている場合は、mod_rewriteを使用してURLの書き換えを行うことでできます。
pathnameモードを使う場合は、アプリケーションがルートのURLで実行するようにしてください。
-
m.route.param
String param(String key)
ラウトのパラメータは、現在アクティブなラウトのシグニチャを元にして、現在のURLから取り出された動的な値です。
パラメータのないラウトは次のようなものです:
"/path/to/page/"パラメータ付きのラウトは次のような文字列です:
"/path/to/page/:id"- ここでは、idがラウトパラメータの名前もし、現在アクティブなラウトが
/dashboard/:userIDで、現在のURLが/dashboard/johndoeだとすると、m.route.param("userID")は"johndoe"を返します。ラウト中のクエリー文字列のパラメータもこのコレクションに自動的に格納されます。
"/grid?sortby=date"- ここでは、m.route.param("sortby")は"date"を返すString key
ラウトパラメータの名前
returns String value
keyにマップされたパラメータの値
Object param()
returns Object params
ラウトのパラメータをすべて含むオブジェクト
-
m.route.buildQueryString
String buildQueryString(Object data)
URI.jsと同じシリアライズ規約を使い、オブジェクトをURIでエンコードされたクエリー文字列にシリアライズします。
Object data
シリアライズしたいオブジェクト
returns String querystring
入力データのシリアライズ化表現
-
m.route.parseQueryString
Object parseQueryString(String querystring)
URI.jsのデシリアライズ規約を用いて、URIエンコードされたクエリー文字列表現されたオブジェクトをデシリアライズします。
String querystring
デシリアライズするURIエンコーディングされたクエリー文字列
returns Object data
デシリアライズしたオブジェクト
リダイレクト
使用方法
APIを使用して他のページにリダイレクトすることもできます。ラウトの定義のセクションのサンプルですでに使っています:
m.route("/dashboard/marysue");
このコードを実行すると、http://server/#/dashboard/marysueにリダイレクトします。
シグニチャ
void route(String path [, any params] [, Boolean shouldReplaceHistory])
String path
リダイレクト先のラウト。もし、Mithrilのラウティングで取り扱っている範囲外のページにリダイレクトする場合は、
window.locationを使うべきです。any params
クエリー文字列として渡されるパラメータ
Boolean shouldReplaceHistory
もしこのパラメータがtrueに設定されると、新しいページを追加するのではなく、現在のヒストリのエントリーを置き換えます。デフォルトはfalseです。
現在アクティブなラウトの取得
使用方法
Mithrilはレンダリングの後に、ネイティブのlocationを更新して、history.pushState APIが正しい履歴のエントリーが表示されるようにします(Chromeの場合はCtrl+H page)。
コントローラ内で、現在アクティブなラウトを取得するには、m.route()を使います。この関数は、m.route.modeで決定されるURLのパーツ(マイナス?もしくは#シンボル - それぞれsearchモードとhash モード時)を返します。
//もしロケーションバーが"http://example.com/?/foo/bar"
//で、m.route.modeが`search`の場合は、
//`currentRoute == "/foo/bar"`
var currentRoute = m.route();
シグニチャ
String route()
returns String route
現在アクティブなラウトを返します。
モードの抽象化
使用方法
このメソッドを使うには、 config仮想エレメントのプロパティを使用します。サンプル:
//`config`の設定を使うことで、`href`内に'#'を書かなくてもよくなる。
m("a[href='/dashboard/alicesmith']", {config: m.route});
この書き方を使用すると、どのm.route.modeが選択されていたとしても、期待通りの実行結果が得られます。href属性の中に?や#をハードコードするのではなく、常に上記のようなイディオムを使うのが良いプラクティスです。
仮想エレメントについての詳細は、m()のドキュメントを参照してください。
シグニチャ
void route(DOMElement element, Boolean isInitialized, Object context, Object vdom)
DOMElement element
ラウトを指す
href属性を持つ<a>エレメント。Boolean isInitialized
このフラグがtrueの場合はこのメソッドは実行されません。これは、仮想DOMエレメント
config属性に対して、メソッドの互換性を維持するために使用します。m()を参照して下さい。Object context
再描画間で状態を保持するオブジェクトです。
Object vdom
configが適用された仮想DOMデータ構造