厄介なポップアップブロックを無理矢理回避する方法
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でうまく動かないことがあった(気がした)ので、確実に開く方法としてフォームを使った方法を紹介しました。
このやり方もブラウザの隙を突いている気がしないでもないので、いずれブロック対象に指定されるかもしれません。
使う場合はそのあたりのことを考慮に入れておいてください。