githubのアレ(history.replaceStateとかhistory.pushStateの話)
会社で下の記事についてリマインドしてもらって、なんとなく気になっていたことを調べたメモ。
http://webtech-walker.com/archive/2010/12/06160539.html
記事を読んで、history.replaceState(null, "title", "/new.html") とかやると遷移なしでページのcontentも勝手に置き換わるのかなー、だったらあのアニメーションはどこで発火してんだ?とか考えていたがそもそもreplaceStateの動作について勘違いしていた。
要は、次のようなhtml書いてボタンをクリックしても、historyの先頭が置き換わるだけでページ自体には何も起こらない。(ただしlocation.hrefは置き換わっており、reloadすると/replace.htmlにいく)
<!DOCTYPE HTML> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> </head> <body> <div id="header"> <h1>へっだー</h1> </div> <div id="container"> <p>1</p> <button id="replace">Replace!</button> </div> <script type="text/javascript"> (function() { var replaceButton = document.getElementById("replace"); replaceButton.addEventListener("click", function(e) { history.replaceState(null, "Replaced Title", "/replace.html"); //history.pushState(null, "Replaced Title", "/replace.html"); alert(location.href); }, false); })(); </script> </body> </html>
ちなみに確認した環境はFirefox4.0b7のみなので、history.replaceStateやらが動く他のブラウザ(ChromeとかSafariとか)でどうなるかは分かりません。
さらに、この記事を読んだ時「ChromeやSafariやFirefox4でパンくずリストやプロジェクトに含まれるファイル名をクリックするとズビビッとスライドしてDOMが置き換わるアレがreplaceStateを使っているのだろう」と思っていたけどそれも違った。replaceStateが使われているのは別の場所。
ソースをじろじろ眺めてみると、そこに使われているのはhistory.pushStateの方で、こっちを使うと現在の位置が置き換えられずにhistoryに残る。AjaxによるDOM更新にhistoryを加えるような使い方には、pushStateの方が適していそう。
先程も書いたようにreplaceState or pushStateするだけでは現在のページのコンテンツには何も起こらないので、githubのあのズビビッでやってるのは
1. pushStateでhistoryにリンクのURLをpush
2. 同URLに?slide=1&_=(\d+)を付加したものをxhrでGET
3. 得られたhtmlを使い、該当部分のDOMを書き換える(ここでアニメーション)
みたいなことのようだ。こうして、一部のURLについて特定のクエリパラメータを渡したときhtmlの一部分だけを返すような実装にし、かつhistory.pushStateとXmlHttpRequestを用いることで
1. location.hrefを更新できる
2. historyに積まれるので前のページに戻れる
3. しかしAjaxでDOMを書き換えるのでページ遷移が発生しない
という三段構えUIを実現している、ということのようですなあ。