expressjs、jade、History.jsを使用した再起動なしのナビゲーション

これまでに自分の作品で、履歴APIなどのHTML5機能を使用したことはありません。 そして、それを理解して小さな実験を行うための時間が来ました。 この実験の結果をあなたと共有することにしました。



そして、私たちが望むもの:

-履歴APIを使用したサイトナビゲーション

-サーバーからjsonオブジェクトとしてデータを受信し、その後クライアントでレンダリングします

-直接遷移の場合、レンダリングはサーバーで発生する必要があります

-すべてが簡単でシンプルになること



さまざまなニーズを決定しましたが、次はテクノロジーを決定します。

-Expressjsはnodejsの下のサーバーで動作します

-ヒスイテンプレートエンジンとして

-クライアントHistory.jsの場合



サーバー


nodejsを使用したことがない場合は、最初にインストールする必要があります。 ここで、Ubuntuですばやく実行する方法を確認できます 。 プロジェクトのフォルダーを作成して、そこに移動します。 次に、必要なモジュールをインストールします。

npm私は玉を表現します



そして、2つのディレクトリを作成します。

-表示-テンプレートはここにあります

-パブリック-静的コンテンツがあります



次に、サーバーを作成し、主なポイントにのみ焦点を当てます。

私が人生を楽にしたかった最初のことは、ajaxリクエストがどのように私たちに届いたかを考えないことでした。 これを行うには、標準のres.renderをインターセプトします

コード
app.all('*', function replaceRender(req, res, next) { var render = res.render, view = req.path.length > 1 ? req.path.substr(1).split('/'): []; res.render = function(v, o) { var data; res.render = render; //         //  if ('string' === typeof v) { if (/^\/.+/.test(v)) { view = v.substr(1).split('/'); } else { view = view.concat(v.split('/')); } data = o; } else { data = v; } // res.locals      //    s (res.locals.title) data = merge(data || {}, res.locals); if (req.xhr) { //     json res.json({ data: data, view: view.join('.') }); } else { //   ,    // (   history api) data.state = JSON.stringify({ data: data, view: view.join('.') }); //    .       . view[view.length - 1] = '_' + view[view.length - 1]; //   res.render(view.join('/'), data); } }; next(); });
      
      









res.renderはオーバーロードされています。 コントローラーでres.render(データ)またはres.render(「ビュー名」、データ)を安全に呼び出すことができ、サーバー自体はリクエストのタイプに応じてjsonをレンダリングするかクライアントに返します。



コードをもう一度見てみましょう。「サーバーでのレンダリング」の場合に、テンプレートのプレフィックス「_」が必要な理由を説明します。

問題は次のとおりです。 ヒスイにはレイアウトがありません。代わりにブロックが使用され、ブロックは相互に拡張、置換、または補完できます(これについてはドキュメントで詳しく説明されています )。



例を考えてみましょう。

次のマッピング構造があると仮定します。

オプションA
layout.jade

 !!! 5 html head title Page title body #content block content
      
      







index.jade

 extends layout block content hello world
      
      







index.jadeをレンダリングすると、layout.jadeと一緒にレンダリングされます。 これは、index.jadeをクライアントにエクスポートしてそこでレンダリングするまで、問題は発生しませんが、layout.jadeはありません。 したがって、これを簡単かつ簡単に行える別のテンプレートを追加することにしました。



オプションB
layout.jade

 !!! 5 html head title Page title body #content block content
      
      







_index.jade

 extends layout block content include index
      
      







index.jade

 hello world
      
      







レイアウトでブロックをレンダリングする場合、_index.jadeファイルをレンダリングします。レイアウトが不要な場合は、index.jadeがレンダリングされます。 この方法は、私には最もシンプルで理解しやすいように思えました。 接頭辞が「_」のテンプレートのみがlayout.jadeを拡張するというルールを順守している場合、他のすべてをクライアントに安全にエクスポートできます。 (これを行うには間違いなく他の方法がありますが、コメントでそれらを伝えることができます。知るのは面白いでしょう)



次に注目するのは、テンプレートをクライアントにエクスポートすることです。 これを行うには、viewdirに関連するテンプレートへのパスを入力として受け取り、出力にキャストされたコンパイル済み関数を出力に返す関数を作成します。

コード
 function loadTemplate(viewpath) { var fpath = app.get('views') + viewpath, str = fs.readFileSync(fpath, 'utf8'); viewOptions.filename = fpath; viewOptions.client = true; return jade.compile(str, viewOptions).toString(); }
      
      







次に、テンプレートを使用してjavascriptファイルを収集するコントローラーを作成します。

コード
(もちろん、すべてがあなたの手であるという事実に注意を払わないでください、これはもちろん、実際のプロジェクトでは、それはする価値がないということです)

 app.get('/templates', function(req, res) { var str = 'var views = { ' + '"index": (function(){ return ' + loadTemplate('/index.jade') + ' }()),' + '"users.index": (function(){ return ' + loadTemplate('/users/index.jade') + ' }()),' + '"users.profile": (function(){ return ' + loadTemplate('/users/profile.jade') + ' }()),' + '"errors.error": (function(){ return ' + loadTemplate('/errors/error.jade') + ' }()),' + '"errors.notfound": (function(){ return ' + loadTemplate('/errors/notfound.jade') + ' }())' + '};' res.set({ 'Content-type': 'text/javascript' }).send(str); });
      
      







クライアントが/テンプレートをリクエストすると、これに応じて次のオブジェクトを受け取ります。

 var view = { ' ': <> };
      
      





クライアントで目的のテンプレートをレンダリングするには、 view ['template name'](data);を呼び出すだけで十分です。



サーバー側の検討を終了します。 他のすべては特に関連するわけではなく、私たちのタスクに直接関連していません。 また、コードはこちらにあります



お客様


コンパイル済みのテンプレートをクライアントにエクスポートするため、テンプレートエンジン自体を接続する必要はなく、 ランタイムに接続するだけで、テンプレートを通常のjavascriptファイルとして接続することでテンプレートをロードすることを忘れないでください。



リストの次のライブラリはHistory.jsで 、その名前はそれ自身を表しています。 ライブラリはハッシュURLを介して古いブラウザーで動作しますが、 html5ブラウザーのみのバージョンを選択しました。これらはすべて最新のブラウザーです。



クライアントコードはほとんど残っていません。

最初に、 render()関数を作成します 。 これは非常に単純で、指定されたテンプレートをコンテンツブロックにレンダリングします。

 var render = (function () { return function (view, data) { $('#content').html(views[view](data)); } }());
      
      







History.jsで動作するようになったコードの初期化

コード
 $(function () { var initState; if (History.enabled) { $('a').live('click', function () { var el = $(this), href = el.attr('href'); $.get(href, function(result) { History.pushState(result, result.data.title, href); }, 'json'); return false; }); History.Adapter.bind(window,'statechange', function() { var state = History.getState(), obj = state.data; render(obj.view, obj.data); }); //init initState = $('body').data('init'); History.replaceState(initState, initState.data.title, location.pathname + location.search); } });
      
      







コードは非常に簡単です。 最初に行うことは、ブラウザーが履歴APIをサポートしているかどうかを確認することです。 そうでない場合は、何も変更しないでください。クライアントは昔ながらの方法で動作します。

そして、それがサポートされている場合、aのすべてのクリックをインターセプトし、ajaxリクエストをサーバーに送信します。



「statechange」イベントハンドラーをハングアップすることを忘れないでください。この時点で、コンテンツブロックを再描画し、初期状態の初期化を追加する必要があります。 本文タグ、 data-init属性に保存することにしました。ここで、初期値はサーバーでのレンダリング時に書き込まれます。

data.state = JSON.stringify({data:data、view:view.join( '。')}); replaceRender関数内



それだけです。



実際の例はこちら (彼が死んだら、Habroeffectが彼を隠してくれた:))

コードはここにあります。



All Articles