記一次小坑--關於window.open()

今天在公司的後臺項目中遇到一個這樣的需求:點擊一個按鈕,發送一個請求,而後用請求到的data中的url打開一個新窗口(跳轉到另外一個後臺)。看起來應該沒什麼問題,很快代碼寫好了(vue項目,如下是僞代碼,主要表達下思路):javascript

clickHandle() {
  api.get('xxx', params).then(response => {
    let data = response.data;
    if(data.code === 0 ) {
      let url = data.data.url || '';
      if (url) {
        window.open(url);
      }
    }
  });
}
複製代碼

愉快地測試下,發現並無彈出新窗口,短促的慌亂以後,發現是瀏覽器攔截了新窗口的打開。。。vue

搜索引擎告訴我,非用戶行爲致使的打開新窗口可能會被部分瀏覽器攔截(在谷歌瀏覽器中,它的表現形式是在地址欄的末尾有一個通知圖標,點擊通知能夠選擇容許仍是繼續攔截)。搜索引擎還說,能夠用手動觸發dom事件的方式模擬用戶行爲,避開瀏覽器的攔截。java

有了上面的思路,我把僞代碼修改以下:api

clickHandle() {
  api.get('xxx', params).then(response => {
    let data = response.data;
    if(data.code === 0 ) {
      let url = data.data.url || '';
      if (url) {
        // window.open(url);
        // 在dom中添加a標籤-註冊點擊事件打開新窗口-觸發點擊事件-從dom中移除a標籤
        let a = document.createElement('a');
        a.id = 'temp';
        document.body.appendChild(a);
        a.addEventListener('click', function(){
          window.open(url);
        });
        a.click();
        document.body.removeChild(a);
      }
    }
  });
}
複製代碼

很好,再次愉快地測試下,然而,瀏覽器仍是攔截了。。。瀏覽器

笑容逐漸淫蕩。笑容逐漸凝固。摔。session

搜索引擎再次告訴我,只要是在異步回調裏執行的window.open()都會被攔截app

好,整理下思路:此次咱們不在異步回調裏window.open()了。點擊按鈕先打開新窗口,把新窗口的引用保存在data裏。請求拿到url後,把url也保存在data裏。而後咱們watch一下url,url有值了,就把新窗口的引用重定向。讓咱們祈禱此次別出什麼幺蛾子。代碼修改以下:dom

export default {
  data() {
    return {
      url: '',
      newWin: null  // 新窗口的引用
    }
  },
  watch: {
    url(newVal, oldVal) {
      if(newVal && this.newWin) {
        this.newWin.location.href = newVal;
        // 重定向後把url和newWin重置
        this.url = '';
        this.newWin = null;
      }
    }
  },
  methods: {
    clickHandle() {
      let _this = this;
      // 先打開一個空的新窗口,再請求
      this.newWin = window.open();
      api.get('xxx', params).then(response => {
        let data = response.data;
        if(data.code === 0 ) {
          _this.url = data.data.url || '';
        }
      });
    }
  }
}
複製代碼

謹慎地測試一下,此次它打開了,它真的打開了。不能說很高興吧,通常高興。異步

然而下一秒,我發現我高興早了:窗口是打開了,但是新窗口中的頁面一直在加載動畫的狀態。我之前以爲這個加載動畫挺好看的,就是一個缺了一塊扇形的大圓不斷地吃着一個個排成一線的小圓的動畫,如今我以爲它吃的好像有點多了。學習

笑容逐漸變態。算了,不笑了。

此次沒用搜索引擎,發現上面那個問題,是由於打開的新窗口會保留舊窗口的sessionStorage(至於爲何sessionStorage會阻止我那個新頁面的加載就不在這篇文章的討論範圍以內了)。知道緣由後,解決方法就簡單了,在重定向以前,把新窗口的sessionStorage清空就行了。也就是在上面代碼的這行代碼this.newWin.location.href = newVal;以前加上一行this.newWin.sessionStorage.clear()就行了。代碼就不放了。

這一次的測試沒出什麼問題。

總結

瀏覽器會攔截新窗口的打開也是爲了保護用戶體驗,能夠屏蔽一些廣告。須要注意的是新窗口的引用newWin其實就是一個新的window對象,天然能使用上面的清除sessionStorage的方法。更多的關於window對象的知識,像是新窗口與打開它的窗口之間的通訊等,能夠在《Javascript高級程序設計》的第8章第1節中查閱學習。

相關文章
相關標籤/搜索