現象
最近在做項目的時候碰到了使用window.open被瀏覽器攔截的情況,搞得人無比郁悶啊,雖然在自己的環境可以對頁面進行放行,但是對用戶來說,不能要求用戶都來通過攔截。何況當出現攔截時,很多小白根本不知道發生了啥,不知道在哪里看被攔截的頁面,簡直悲催啊~~。
另外,可以發現,當window.open為用戶觸發事件內部或者加載時,不會被攔截,一旦將彈出代碼移動到ajax或者一段異步代碼內部,馬上就出現被攔截的表現了。
原因分析&深入研究
當瀏覽器檢測到非用戶操作產生的新彈出窗口,則會對其進行阻止。因為瀏覽器認為這不是一個用戶希望看到的頁面。
比如對js中直接執行的,如下代碼:
// 直接打開一個頁面 window.open(‘//www.baidu.com‘, ‘_blank‘);
瀏覽器 | ie8 | chrome 40 | firefox 34 | opera 27 | safari 5.1.7 |
---|---|---|---|---|---|
是否阻止彈出 | N | N | Y | Y | Y |
而對於如下代碼:
document.body.addEventListener(‘click‘, function() { window.open(‘//www.baidu.com‘, ‘_blank‘); });
所有瀏覽器都不會攔截。
綜上所述,各瀏覽器對攔截時機的判斷不一致,而對於放在ajax回調中的代碼,反應又不相同了,這里就不再贅述。但是,被瀏覽器攔截我們代碼中要彈出的窗口並不是程序員所希望的。
解決方案:
1、使用a標簽替代
給出如下函數,將此函數綁定到click的事件回調中,就可以避免大部分瀏覽器對窗口彈出的攔截:
function newWin(url, id) { var a = document.createElement(‘a‘); a.setAttribute(‘href‘, url); a.setAttribute(‘target‘, ‘_blank‘); a.setAttribute(‘id‘, id); // 防止反復添加 if(!document.getElementById(id)) { document.body.appendChild(a); } a.click(); }
2、使用form的submit方法打開一個頁面
這種方法需要構造一個from,然后由js代碼觸發form的submit,將表單提交到一個新的頁面,代碼較長,在這里就不寫了,大家知道有這種方案就行了。
大家注意,以上兩種方法不適合放在ajax的回調函數中,如果放在回調函數中,依然會被瀏覽器攔截。
3、終極解決方案–先彈出窗口,然后重定向
第三種方案,其實是一種變通方案,核心思想是:先通過用戶點擊打開頁面,然后再對頁面進行重定向。示例代碼如下。
xx.addEventListener(‘click‘, function () { // 打開頁面,此處最好使用提示頁面 var newWin = window.open(‘loading page‘); ajax().done(function() { // 重定向到目標頁面 newWin.location.href = ‘target url‘; }); });
以上方法其實是打開了兩個地址,所以建議大家打開第一個地址的時候給出一個類似‘當前頁面正在加載中,請稍后。。’的簡單提示頁,這樣可以避免打開兩次真正的目標頁面,讓用戶察覺到頁面的重定向。