はじめに(完全に余談)
本投稿は、ちょっと前に書いたブラウザで別タブ・別ウィンドウを開いたことを検知する方法という記事の続きと言うか補足になる。実際の現場では、前回書いた内容だけではほぼ使えないと思う。具体的には、ブラウザ(IE
とかSafari
とか…こいつらホンマに嫌い…)によっては意図した動作をしないこともあるけん。
いくつか注意すべき点があるので、備忘録的に書き残す。
注意点その1:別タブが開いたことを検知できない
注意点として、onblur
やonfocus
イベントだけだと、別タブが開いたことは検知できない。。。
なので、別タブが開いたときに何か処理をする対応が必要となる。それにはonload
イベントを使うのがよろし。
$(window).on('load', function() { // 何らかの処理 });
注意点その2:onload
イベントだと別タブか画面遷移か判断がつかない
form
だったり、リンクによる画面遷移の場合も、onload
イベントは発火してしまう。
なので、これは画面遷移だ!これは別タブだ!と判断するための処理が必要になるが、これはリファラを見るか履歴を見ればいい。
画面遷移ならば、以下の方法でリファラが取得できる。
- JavaScript:
document.referrer
- PHP:
$_SERVER['HTTP_REFERER']
さらにhistory.length == 1
ならば、新規に開いたことになる。(同画面ならばそれまでの履歴が存在するはず)
注意点その3:タブの複製
これ。(注意点その2にも関連しているが)ある意味一番悩ましいタブの複製
。
ブラウザのタブの部分で右クリックした際に現れるこいつは、リファラだろうが、URLのクエリだろうが、jsの変数の中身だろうが、
ブラウザ側の全てをコピーしてしまうので、タブを一意にしたい場合、こればっかりは対処しようがない…
一応無理やり判断する方法としては、JavaScriptのwindowオブジェクトに存在するlocalStorage, sessionStorage
(*1)を使ってみた。(※ IEだとインターネットオプションからDOMストレージ
を有効に設定してないと動かないらしいです!)
さて、この2つは機能としてはほとんど同じなのだが以下の点が異なる。
- localStorage: 全てのタブでデータを共有できる(*2)
- sessionStorage: データはタブごとに一意
使い方はどちらも同じでsetItem('key', val), getItem('key')
という2つのメソッドを使う。
自分は各タブごとにランダムなIDを発行し、それをsessionStorage
に保存して識別。タブの複製は判断がつかないため、onload
イベントのたびに新しくIDを再発行し、それをsessionStorage
に保存する。一応ランダムにIDを発行していたが、万が一被る可能性もあるため、localStorage
にもIDを保存しておき、重複チェックもかけることで一意性を担保していた。(この場合画面遷移でも新しく発行され直すが、それは問題なかったのでそのまま)
注意点その4:onblur
やonfocus
イベントのタイミングが違う
ブラウザやそのバージョンによってはこれらの動作するタイミングが逆だったりする。 自分が検証したものだとこんな感じ。
ブラウザ | blur |
focus |
---|---|---|
IE(v11) | 後 | 先 |
Google Chrome | 先 | 後 |
Firefox | 先 | 後 |
Safari | バージョンや端末に寄っては逆(*3) | - |
この点を踏まえた上で、
- バックエンドに何をさせるのか
- フロントエンドに何を返すのか
- フロントエンドに何をさせるのか
- イベント(プロセス)は管理できているか
これらを考慮した実装をしないといけない。
(自分はタブごとにセッションを持たせる実装をしようとしたが、これがくっそ大変だった…
FuelPHP
の仕様もあいまって処理の順番がぐっちゃぐちゃに…)
終わりに
深く踏み込み始めて色々見えてきたが、まぁ別タブ対応は面倒だわ。この記事が少しでもいろんな人の助けになれば幸い。