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/page
hash
モードはハッシュ(#以降
)を使います。このモードは唯一、どのブラウザでもページリフレッシュが発生しません。しかし、このモードでは名前付きアンカーが使えなくなります。サンプルURL:
http://server/#/path/to/page
pathname
モードは特別な文字を含まないURLを許可します。しかし、このモードでブックマークとページリフレッシュをサポートするためには、サーバ側にも手を加える必要があります。IE8上では、常にページリフレッシュが発生します。サンプルURL:
http://server/path/to/page
pathnameモードを使用するためのサーバ設定の中で、一番簡単な方法は、どの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データ構造