Web Developer's Struggle Memories

日々の業務から思ったこと、学んだことを書き連ねていきます。

続・ブラウザで別タブ・別ウィンドウを開いたことを検知する方法の問題点

はじめに(完全に余談)

本投稿は、ちょっと前に書いたブラウザで別タブ・別ウィンドウを開いたことを検知する方法という記事の続きと言うか補足になる。実際の現場では、前回書いた内容だけではほぼ使えないと思う。具体的には、ブラウザ(IEとかSafariとか…こいつらホンマに嫌い…)によっては意図した動作をしないこともあるけん。

閑話休題

 
いくつか注意すべき点があるので、備忘録的に書き残す。

注意点その1:別タブが開いたことを検知できない

注意点として、onbluronfocusイベントだけだと、別タブが開いたことは検知できない。。。 なので、別タブが開いたときに何か処理をする対応が必要となる。それにはonloadイベントを使うのがよろし。

$(window).on('load', function() {
   // 何らかの処理
});


注意点その2:onloadイベントだと別タブか画面遷移か判断がつかない

formだったり、リンクによる画面遷移の場合も、onloadイベントは発火してしまう。 なので、これは画面遷移だ!これは別タブだ!と判断するための処理が必要になるが、これはリファラを見るか履歴を見ればいい。

画面遷移ならば、以下の方法でリファラが取得できる。

さらに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:onbluronfocusイベントのタイミングが違う

ブラウザやそのバージョンによってはこれらの動作するタイミングが逆だったりする。 自分が検証したものだとこんな感じ。

ブラウザ blur focus
IE(v11)
Google Chrome
Firefox
Safari バージョンや端末に寄っては逆(*3 -

この点を踏まえた上で、

  • バックエンドに何をさせるのか
  • フロントエンドに何を返すのか
  • フロントエンドに何をさせるのか
  • イベント(プロセス)は管理できているか

これらを考慮した実装をしないといけない。 (自分はタブごとにセッションを持たせる実装をしようとしたが、これがくっそ大変だった… FuelPHPの仕様もあいまって処理の順番がぐっちゃぐちゃに…)

終わりに

深く踏み込み始めて色々見えてきたが、まぁ別タブ対応は面倒だわ。この記事が少しでもいろんな人の助けになれば幸い。

*1:この子らはIE8以上、FireFoxChromeSafariで対応している

*2:厳密には一ドメインで一つのストレージなので別の画面でもいける

*3:基本的には最新のものを使っている