Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.
SPA のルーティングの話
NDS Meetup #12
ushiboy
SPA とは
SPA ( Single Page Application )とは
単一の Web ページで構成される Web アプリケーションや Web サイト
デスクトップアプリケーションのような UX を実現する
画面の切り替えは JavaScript ...
SPA ルーティングの方法
2通りの方法がある
Hash
History API
Hash
Hash によるルーティング
URL の Hash (フラグメント識別子)を利用した方法
location.hash
hashchange イベント
http://localhost:8080/path/to#hoge
Hash ( JavaScript でのルートの扱い)
location.hash を使う
遷移先ルートの設定
location.hash = 'hoge';
現在のルートの取得
console.log(location.hash); // -...
(補足) location
http://localhost:8080/path/to?a=1&b=2#hoge
protocol http:
host localhost:8080
hostname localhost
port 8080
o...
Hash ( a タグでの扱い)
a タグでは通常通りに href 属性で定義する
<a href="#hoge">Hoge</a>
<a href="#fuga">Fuga</a>
<a href="#piyo">Piyo</a>
hashchange イベント
Hash が変わった時に発生する
location.hash === '#aaa' の時に location.hash = 'aaa' しても発生しない
イベントリスナーで変更前と変更後の URL が取得できる
...
Hash でのルーティングの動き
ページロード時
現在のルート( location.hash の値)に応じて画面を表示する
ユーザーの画面遷移操作
location.hash を変更する
hashchange イベント
現在のルート( loca...
Hash でのルーティングの特徴
Hash より前の URL の要素(パスとか)は変化しない
http://localhost:8080/path/to#hoge
ブラウザは Hash を HTTP リクエストとしてサーバへ送らない
サーバサイ...
(余談) escaped fragment
Google が過去に出した Hash なルーティングをクロールしてくれる仕組み
現在は Deprecated
「 #! 」みたいな感じでやっていた
https://developers.google...
History API
History API によるルーティング
History API を利用した方法
location.pathname ( location.search, location.hash )
history.state
history.pushS...
History API ( JavaScript でのルートの扱い)
サーバにリクエストが行かないように次のようにする
遷移先ルートの設定
history.pushState(state, title, '/hoge');
現在のルートの取得
...
History API ( a タグでの扱い)
サーバにリクエストが行かないようにクリックのデフォルト挙動を止める
<a href="/hoge">Hoge</a>
function handleClick(e) {
e.preventDefa...
popstate イベント
ブラウザの戻る・進むで発生する
history.pushState メソッドを実行したタイミングで起こるわけではない
イベントリスナーで状態が取得できる
window.addEventListener('popsta...
History API でのルーティングの動き
ページロード時
現在のルート( location.pathname の値)に応じて画面を表示する
history.state から状態を取り出して利用する
ユーザーの画面遷移操作
history....
History API でのルーティングの特徴
状態をオブジェクトとして保存できる
同じ origin のパスならどこでも書き換えられる
http://localhost:8080/path/to
サーバ側で rewrite が必要になる
ap...
History API の開発環境
開発用に Web サーバを起動して使っているようなケース
何もしないと URL のパスにアクセスしてしまって 404 になる
historyApiFallback を使う
connect を使っている場合は ...
Hash と History API の比較
Hash History API
難易度 お手軽 いろいろ考慮が必要
サーバサイドの設定 不要 必要
サーバサイドレンダリング できない できる
状態の保持 なし あり
用途 裏画面
Electro...
URL のルーティング定義
サーバサイドでやってたときと同じ感じ
Hash
一覧画面系だったら #/users
詳細画面系だったら #/users/1
History API
一覧画面系だったら /users
詳細画面系だったら /users/...
まとめ
SPA ではクライアントサイドでルーティングが必要になる
ルーティングの方法は 2 通り
Hash
History API
SPA ルーティングあるある
「 SPA ルーティングあるある」と書きましたが ...
SPA のルーティングでやらかしてきた話
要は失敗談
ブラウザで戻ると壊れる
ブラウザで戻ると壊れる
ルーティング管理外の画面を入れてしまっときに起こる
一覧から選択して詳細に行くやつとか
ツリーを展開していくやつとか
ウィザード的に進んでいくやつとか
一つ前に戻ったつもりが、予想もしていなかった画面に戻る
まったくルー...
リロードすると壊れる
リロードすると壊れる
状態やパラメータをメモリ中にしか持っていなかった場合に起こる
Ajax でデータ取ってくるためのパラメータがなくて取れないとか
絞り込み条件フォームの入力状態がクリアされてしまうとか
ページネーションのページ番号がリセット...
URL を共有したら壊れる
URL を共有したら壊れる
URL にパラメータが含まれていない場合に起こる
ページネーションのパラメータとか
http://localhost:8080/users?page=10
検索条件のパラメータとか
http://localhost:...
別タブで開けなくなる
別タブで開けなくなる
a タグのクリックイベント制御が雑だと起こる
Ctrl +クリックやミドルクリックとかで別タブで開こうとすると開けない
⇒ 押されているボタンを調べて正しくハンドリングする
el.addEventListener('cli...
まとめ(反省)
思った以上にブラウザの標準機能は使っている
ブラウザの標準機能を自然に使えるようにする必要がある
開発中も戻る・進むなどの動きをよく確認しておく
状態をどこに・どこまでもたせるかよく考える
Nächste SlideShare
Wird geladen in …5
×

SPAのルーティングの話

12.669 Aufrufe

Veröffentlicht am

NDS Meetup #12

Veröffentlicht in: Technologie
  • Login to see the comments

SPAのルーティングの話

  1. 1. SPA のルーティングの話 NDS Meetup #12 ushiboy
  2. 2. SPA とは
  3. 3. SPA ( Single Page Application )とは 単一の Web ページで構成される Web アプリケーションや Web サイト デスクトップアプリケーションのような UX を実現する 画面の切り替えは JavaScript による DOM 操作で行う クライアントサイドで URL に応じた画面を表示(ルーティング)する
  4. 4. SPA ルーティングの方法 2通りの方法がある Hash History API
  5. 5. Hash
  6. 6. Hash によるルーティング URL の Hash (フラグメント識別子)を利用した方法 location.hash hashchange イベント http://localhost:8080/path/to#hoge
  7. 7. Hash ( JavaScript でのルートの扱い) location.hash を使う 遷移先ルートの設定 location.hash = 'hoge'; 現在のルートの取得 console.log(location.hash); // -> '#hoge'
  8. 8. (補足) location http://localhost:8080/path/to?a=1&b=2#hoge protocol http: host localhost:8080 hostname localhost port 8080 origin http://localhost:8080 pathname /path/to search ?a=1&b=2 hash #hoge href http://localhost:8080/path/to?a=1&b=2#hoge
  9. 9. Hash ( a タグでの扱い) a タグでは通常通りに href 属性で定義する <a href="#hoge">Hoge</a> <a href="#fuga">Fuga</a> <a href="#piyo">Piyo</a>
  10. 10. hashchange イベント Hash が変わった時に発生する location.hash === '#aaa' の時に location.hash = 'aaa' しても発生しない イベントリスナーで変更前と変更後の URL が取得できる window.addEventListener('hashchange', e => { const { newURL, oldURL } = e; console.log(newURL); // http://localhost/#test console.log(oldURL); // http://localhost/ }, false); ページロード時には発生しない ブラウザの戻る・進むでは Hash が変われば発生する
  11. 11. Hash でのルーティングの動き ページロード時 現在のルート( location.hash の値)に応じて画面を表示する ユーザーの画面遷移操作 location.hash を変更する hashchange イベント 現在のルート( location.hash の値)に応じて画面を表示する
  12. 12. Hash でのルーティングの特徴 Hash より前の URL の要素(パスとか)は変化しない http://localhost:8080/path/to#hoge ブラウザは Hash を HTTP リクエストとしてサーバへ送らない サーバサイドレンダリングできない
  13. 13. (余談) escaped fragment Google が過去に出した Hash なルーティングをクロールしてくれる仕組み 現在は Deprecated 「 #! 」みたいな感じでやっていた https://developers.google.com/webmasters/ajax-crawling/docs/getting-started
  14. 14. History API
  15. 15. History API によるルーティング History API を利用した方法 location.pathname ( location.search, location.hash ) history.state history.pushState ( history.replaceState ) popstate イベント http://localhost:8080/path/to/hoge
  16. 16. History API ( JavaScript でのルートの扱い) サーバにリクエストが行かないように次のようにする 遷移先ルートの設定 history.pushState(state, title, '/hoge'); 現在のルートの取得 console.log(location.pathname); // -> '/hoge'
  17. 17. History API ( a タグでの扱い) サーバにリクエストが行かないようにクリックのデフォルト挙動を止める <a href="/hoge">Hoge</a> function handleClick(e) { e.preventDefault(); const { href } = e.target; const state = { /* なんらかの状態 */ }; history.pushState(state, null, href); } Array.from(document.querySelectorAll('a')).forEach(el => { el.addEventListener('click', handleClick, false); });
  18. 18. popstate イベント ブラウザの戻る・進むで発生する history.pushState メソッドを実行したタイミングで起こるわけではない イベントリスナーで状態が取得できる window.addEventListener('popstate', e => { const { state } = e; console.log(state); }, false); ページロード時には発生しない
  19. 19. History API でのルーティングの動き ページロード時 現在のルート( location.pathname の値)に応じて画面を表示する history.state から状態を取り出して利用する ユーザーの画面遷移操作 history.pushState で遷移先ルートを設定する 遷移先ルートの画面を表示する popstate イベント 現在のルート( location.pathname の値)に応じて画面を表示する e.state から状態を取り出して利用する
  20. 20. History API でのルーティングの特徴 状態をオブジェクトとして保存できる 同じ origin のパスならどこでも書き換えられる http://localhost:8080/path/to サーバ側で rewrite が必要になる apache -> mod_rewrite nginx -> rewrite サーバサイドレンダリングと組み合わせることができる
  21. 21. History API の開発環境 開発用に Web サーバを起動して使っているようなケース 何もしないと URL のパスにアクセスしてしまって 404 になる historyApiFallback を使う connect を使っている場合は connect-history-api-fallback をミドルウェアに使う webpack-dev-server の場合はオプションで有効にする
  22. 22. Hash と History API の比較 Hash History API 難易度 お手軽 いろいろ考慮が必要 サーバサイドの設定 不要 必要 サーバサイドレンダリング できない できる 状態の保持 なし あり 用途 裏画面 Electron アプリ 表画面
  23. 23. URL のルーティング定義 サーバサイドでやってたときと同じ感じ Hash 一覧画面系だったら #/users 詳細画面系だったら #/users/1 History API 一覧画面系だったら /users 詳細画面系だったら /users/1 ライブラリでの定義フォーマットもサーバサイドと同じ感じ /users/:id みたいな感じ
  24. 24. まとめ SPA ではクライアントサイドでルーティングが必要になる ルーティングの方法は 2 通り Hash History API
  25. 25. SPA ルーティングあるある
  26. 26. 「 SPA ルーティングあるある」と書きましたが ... SPA のルーティングでやらかしてきた話 要は失敗談
  27. 27. ブラウザで戻ると壊れる
  28. 28. ブラウザで戻ると壊れる ルーティング管理外の画面を入れてしまっときに起こる 一覧から選択して詳細に行くやつとか ツリーを展開していくやつとか ウィザード的に進んでいくやつとか 一つ前に戻ったつもりが、予想もしていなかった画面に戻る まったくルーティング入れないとブラウザの新規タブ開いた状態に戻ったりする ⇒ 意識してルーティング管理下に置く
  29. 29. リロードすると壊れる
  30. 30. リロードすると壊れる 状態やパラメータをメモリ中にしか持っていなかった場合に起こる Ajax でデータ取ってくるためのパラメータがなくて取れないとか 絞り込み条件フォームの入力状態がクリアされてしまうとか ページネーションのページ番号がリセットされるとか ⇒ 必要に応じてメモリ以外の場所に保持しておく
  31. 31. URL を共有したら壊れる
  32. 32. URL を共有したら壊れる URL にパラメータが含まれていない場合に起こる ページネーションのパラメータとか http://localhost:8080/users?page=10 検索条件のパラメータとか http://localhost:8080/users?group=developers ⇒ URL (クエリストリングなど)で持つべきものは持っておく
  33. 33. 別タブで開けなくなる
  34. 34. 別タブで開けなくなる a タグのクリックイベント制御が雑だと起こる Ctrl +クリックやミドルクリックとかで別タブで開こうとすると開けない ⇒ 押されているボタンを調べて正しくハンドリングする el.addEventListener('click', e => { // button 0:left 1:middle 2:right if (e.button === 1 || e.shiftKey || e.altKey || e.ctrlKey || e.metaKey) { return; // skip } e.preventDefault(); } , false);
  35. 35. まとめ(反省) 思った以上にブラウザの標準機能は使っている ブラウザの標準機能を自然に使えるようにする必要がある 開発中も戻る・進むなどの動きをよく確認しておく 状態をどこに・どこまでもたせるかよく考える

×