解決window.open()被瀏覽器攔截的問題

一、問題描述

最近在做項目的時候碰到瞭使用window.open被瀏覽器攔截的情況,雖然在自己的環境可以對頁面進行放行,但是對用戶來說,不能要求用戶都來通過攔截。何況當出現攔截時,很多用戶根本不知道發生瞭啥,不知道在哪裡看被攔截的頁面。因此必須通過代碼來解決這個問題!

以下是瀏覽器攔截示例:

二、問題分析

瀏覽器之所以攔截新開窗口是因為該操作並不是用戶主動觸發的,所以它認為這是不安全的就攔截瞭,即使 ajax 回調函數中模擬執行 click 或者 submit 等用戶行為(trigger('click')),瀏覽器也會認為不是由用戶主動觸發的,因此不能被安全執行,所以被攔截。

三、window.open()語法

window.open(url, name, features, replace)
  Arguments – 參數  url
  可選字符串參數,指向要在新窗口中顯示的文檔的URL。如果省略該參數,或者參數為空字符串,新窗口不會顯示文檔。
  name
  可選字符串參數,該參數可以設置新窗口的名稱。
  相同name的窗口隻能創建一個,要想創建多個窗口則name不能相同。
  features
  可選字符串參數,該參數用於設定新窗口的功能。因為該參數是可選的,如果沒有指定該參數,新窗口有所有的標準功能。
  replace
  可選佈爾參數,設置新窗口中的操作歷史的保存方式。
  true – 創建新歷史記錄
  false – 替換舊的歷史記錄
Returns – 返回值
  一個根據name參數對新創建的或已存在的窗口對象的引用。
Description – 描述
  open()方法可以查找一個已經存在的或者新建的瀏覽器窗口。如果name參數指定瞭一個已經存在的劉瀏覽器窗口,則返回對該窗口的引用。返回的窗口中將顯示URL中指定的文檔,但是features參數會被忽略。open()方法是JavaScript中唯一通過名稱獲得瀏覽器窗口引用的途徑。
  如果沒有指定name參數,或者不存在name參數指定的名稱的窗口,open()方法將創建一個新的瀏覽器窗口。
  name參數用於指定新窗口的名稱,該名稱必須由字母、數字和下劃線字符組成。它可以被HTML文檔中的<a>標記或<form>標記指向。
  當你使用window.open()方法加載一個新的文檔到一個已經存在瞭命名的窗口中時,你可以通過replace參數設置歷史記錄的保存方式.。如果該參數是true, 新文檔的歷史記錄將取代舊文檔的歷史記錄。 如果該參數為false或這沒有指定該參數,新的文件在窗口的瀏覽歷史記錄中將建立自己的條目。該參數提供瞭location.replace()相同功能的方式。
  不要把"Window.open( ) "和"Document.open( )"混淆;這是兩個完全不一樣的方法。為瞭讓代碼更明晰,你可以用"Window.open( )"代替 "open( )"。作為HTML屬性定義事件處理程序時, "open( )" 一般被解釋為"Document.open( )",所以在這種情況下,你必須使用"Window.open( )"。
Window Features – 窗口特性
  feature參數是一個用逗號分隔的功能列表。如果該參數為空或者沒有指定該參數,新的窗口將擁有所有的功能。另一方面, 如果feature參數隻指定瞭某一項或某幾項功能,那麼其他沒有被指定的功能將不會出現在新的窗口中。該字符串不能包含任何空格或其它空字符串。
  列表中的每個元素的格式:功能[=值]
  對於絕大多數的功能來說,它們的值一般都是yes或no。對這些功能,等號和值都可以省略不寫。 對於 width和height特性,必須給它們指定一個以像素為單位的值。
  一下是一些普遍支持的功能和它們的含義:
  height
  設定窗口顯示區域的像素寬度
  left
  瀏覽器窗口距離屏幕左邊的距離
  location
  指明地址欄在新窗口中是否可見
  menubar
  指明菜單欄在新窗口中是否可見
  resizable
  指明新窗口是否可以調整大小
  scrollbars
  指明滾動欄在新窗口中是否可見
  status
  指明狀態欄在新窗口中是否可見
  toolbar
  指明工具欄在新窗口中是否可見
  top
  設定新窗口距屏幕上方的距離
  width
  設定窗口顯示區域的像素寬度
  alwaysLowered
  指定窗口隱藏在所有窗口之下
  alwaysRaised
  指定窗口浮在所有窗口之上
  dependent
  指定打開的窗口為父窗口的一個子窗口。並隨父窗口的關閉而關閉
  directions
  指定Navigator 2和3的目錄欄是否在新窗口中可見
  hotkeys
  在沒有菜單欄的新窗口設置安全退出熱鍵
  innerHeight
  設置新窗口中文檔的像素高度
  innerWidth
  設置新窗口中文檔的像素寬度
  menubar
  指明菜單欄在新窗口中是否可見
  outerHeight
  設定窗口(包括裝飾邊框)的像素高度
  outerWidth
  設定窗口(包括裝飾邊框)的像素寬度
  screenX
  設定新窗口離屏幕邊界的像素長度
  screenY
  設定新窗口離屏幕上邊界的像素長度
  titlebar
  指明菜單題目欄在新窗口是否可見
  z-look
  在文檔中包含各個 <pplet>標簽的數組
  fullscreen
  打開的窗體是否進行全屏顯示

四、代碼模擬

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>測試彈框攔截</title>
  <script>
    window.open("http://www.cnblogs.com/chenyablog/","測試彈框","top=nInt,left=nInt,width=nInt,height=nInt,location=yes,menubar=no,resizable=yes,scrollbars=yes,status=no,toolbar=no");
  </script>
</head>
<body>
   <h1>測試彈框攔截</h1>
</body>
</html>

五、解決方案在

ajax請求之前,先用window.open 打開一個空白窗口,然後在ajax的響應函數中設置該窗口的location屬性為新的url。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>測試彈框攔截</title>
  <script>
    async displayProjectileFrame (type) {
      const title = '測試彈框攔截'
      // 先打開一個窗口
      let newWindow = window.open()
      //給新窗口設置標題
      newWindow.document.title = title
      try {
        const base = 'xxxxxxxxxx'
          // 這裡是模擬ajax,不同使用場景需要有所變化
        const openUrl = await this.$axios.$get('/xxx/xxxx', {
          params: {
            base
          }
        })
        if (openUrl) {
          // 重定向
          newWindow.location = openUrl
        }
      } catch (e) {
        this.$axiosError(e)
      }
    }
  </script>
</head>
<body>
   <h1>測試彈框攔截</h1>
</body>
</html>

六、小結

上面方法,存在一個問題時,因為先打開瞭空白窗口,如果ajax請求失敗(網絡或業務邏輯問題)後, 新窗口中就不會有正常的結果體現,有可能造成用戶疑惑。

一個解決辦法是,當ajax出現問題時,可以考慮給出一個提示,如   newWindow.document.write("服務器處理異常");

甚至為瞭防止ajax響應時間過長,當窗口新建後,立即給出提示  newWindow.document.write("服務器正在處理中,請稍後");

後面如果ajax正常返回,則因為設置瞭location值,原來打印的信息會被新的頁面信息覆蓋。

七、思考

對於動態打開新窗口,沒有特別完美的方法。具體還需根據特定的業務場景來采取相應的做法!

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀: