厄介なポップアップブロックを無理矢理回避する方法
2010/12/01
window.openで新しいウィンドウを開きたいのに、ポップアップブロックに邪魔されて開けないときがあります。
この解決方法をEvernoteサイトメモリーの対応をしているときに発見したので紹介します。
なぜ開かないのか
開かないパターンを知るために、いくつかサンプルを用意しました。
開くパターン
1)直接window.openを実行する
<a href="javascript:void(0)" onclick="window.open('http://www.mapion.co.jp', '_blank', 'width=500,height=480');return false;">ウィンドウを開く</a>
2)関数内で素直に実行
<script type="text/javascript"> function openWindow() { window.open('http://www.mapion.co.jp', '_blank', 'width=500,height=480'); } </script> <a href="javascript:void(0)" onclick="openWindow();return false;">ウィンドウを開く</a>
開かないパターン
1)タイマー内で実行(Firefoxでは開きます)
<script type="text/javascript"> function openWindowTimer() { setTimeout(function(){ window.open('http://www.mapion.co.jp', '_blank', 'width=500,height=480'); }, 100); } </script> <a href="javascript:void(0)" onclick="openWindowTimer();return false;">ウィンドウを開く</a>
2)非同期コールバック内で実行
<script type="text/javascript"> function openWindowAsynchronous() { $.get('/', function(data){ window.open('http://www.mapion.co.jp', '_blank', 'width=500,height=480'); }); } </script> <a href="javascript:void(0)" onclick="openWindowAsynchronous();return false;">ウィンドウを開く</a>
3)onload内で実行
ChromeとSafariで開かないことを確認しています。コードは割愛。
開かないパターンを上記の例から推測すると以下のようになります。
- ユーザーが起こしたアクションではない
- 途中で(非同期やコールバックなどのため)処理が分断されている
※一度ポップアップがブロックされると、その後もブロックし続けるブラウザもあるので注意。
ポップアップブロックを回避する裏技
一番妥当なのは直接実行させる範囲内に収めることですが、それだけではどうしても対応できない場合があります。
例えば、クリック→非同期で必要なデータを取得→window.openなど。
そこで、裏技です。
- 非同期実行のコールバックでwindow.openを指定せず、取得したデータのみ変数に格納
- ブロックされないタイミングで、先に空のwindowを開く
- 非同期取得時に格納されるデータをsetIntervalで監視。
値の取得を確認できたら、formを作成、actionとmethodとtarget(先に開いている空のwindow)を指定→bodyに追加してsubmitで送信する。
以下サンプル
<script type="text/javascript"> function openWindowSendForm() { var tmp; $.get('/', function(data){ tmp = data; }); // ここで先に開きます。 targetは必ず指定。 window.open('', 'openTest', 'width=500,height=480,resizable=yes'); var count = 0; var timerID = setInterval(function(){ if (tmp) { // 非同期のデータが取得できたことを確認したらフォームからデータを送信 sendData(); clearInterval(timerID); return; } count++; if (count > 10) clearInterval(timerID); }, 100); } function sendData(){ var attributes = { action : "http://www.google.co.jp", method : "get", target : "openTest" } var form = document.createElement("form"); for (var key in attributes) { form.setAttribute(key, attributes[key]); } form.style.display = "none"; var body = document.getElementsByTagName("body")[0]; body.appendChild(form); form.submit(); } </script> <a href="javascript:void(0)" onclick="openWindowSendForm();return false;">ウィンドウを開く</a>
確認できる範囲のブラウザでブロックされずWindowが開きます。
ポイントは、ブロックされないところで空のwindowをtarget名を指定して開くこと。
そして、指定したtargetに向けてformを投稿することです。
※ただしこの方法ではonloadのブロックには対応しません。
実は、わざわざフォームを作成せずに、再度window.openを実行しても問題なく実行されたりします。 ただ、Mac版のChromeかSafariでうまく動かないことがあった(気がした)ので、確実に開く方法としてフォームを使った方法を紹介しました。
このやり方もブラウザの隙を突いている気がしないでもないので、いずれブロック対象に指定されるかもしれません。
使う場合はそのあたりのことを考慮に入れておいてください。