pushState, popStateを使ってURLの履歴を追加したり、ブラウザバックに対応したりする事ができるので画面遷移をせずにAjaxとかで画面を切り替えるサイトを作ることができます。
で、記事の概要をクリックされたら、Ajaxで記事内容を取ってきて全面モーダルで表示。その際にpushStateでURLを記事のURLに変更、モーダルが閉じられたら元のURLに戻すようなサイトを作成していました。
久しぶりにサイトの修正があり確認しに行った所、Safariでページがロードされた時にpopstate
で登録してたイベントが実行されている現象に遭遇しました。
例
$(function() { var w = window, d = document; if(w.history && w.history.pushState) { $(d).on('click', '#push', function(evt) { console.log('>> pushstate'); evt.preventDefault(); var q = w.location.search.substring(1), res = {count: 0}, url; q = q.split("&"); for(var i=0, l=q.length; i<l; i+=1) { var parm = q[i].split('='); res[parm[0]] = parm[1]; } url = '?count=' + (res['count'] - 0 + 1); history.pushState('', '', url); }); $(w).on('popstate', function() { console.log('<< popstate'); history.go(0); history.replaceState('back', '', w.location.pathname); }); } });
#push
の要素をクリックする度にurlのパラメーターの?count=
の値が増えて、ブラウザバックするとパラメーターなしのURLになるっていうすごい意味の分からないコードです!
これをSafari (9.0.3)で開くと初回ロード時にpopstate
イベントが呼びだされ延々画面がリロードされますwww
手持ちのChrome (48.0.2564.116)、Firefox (44.0.2)、Vivaldi (1.0.344.37) では初回ロード時にpopstate
イベントが呼ばれている事はありませんでした。
※ SafariなのでiOSのブラウザでも同様の現象が発生しているかもしれません。
自分でpopStateしたものかどうかチェックする事で初回ロード時かどうか判別する。
popstate
イベントで呼び出される関数の引数でpushState
した時のstateを取得する事ができるようです。
これを利用すると意図してpushStateされたものかどうか判断ができるので、初回ロード時は処理を行わないという事ができそうです。
先のコードを修正します。
// 略 $(d).on('click', '#push', function(evt) { /* 中略 */ // 第1引数で state を指定する history.pushState('count', '', url); }); $(w).on('popstate', function(evt) { console.log('<< popstate', evt.originalEvent.state); // state がなければ何もしない if(!evt.originalEvent.state) { return; } history.go(0); history.replaceState('back', '', w.location.pathname); }); // 略
これで、Safariでウィンドウのロード時にpopstateの処理が実行されることは無くなりましたが、
stateが設定されていないと、上手く動作しないので自分で意図してpushState()
、replaceState()
したか解るように第一引数にキチンとstateオブジェクトを指定しなければなりません。
たぶんデフォルトだとevt.originalEvent.state
はnull
だと思うので、stateオブジェクトを指定せずに空文字列のままにしておき、null
出ない時で判別することもできなくはないと思いますが、stateオブジェクトを指定しておくほうが幸せになれるんじゃないかなぁ―と思います。
[参考]

- 作者: Nicholas C. Zakas,和田祐一郎
- 出版社/メーカー: オライリージャパン
- 発売日: 2014/06/18
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る