js 開啟新視窗方式

yiiouo發表於2019-02-16

之前的專案,有個功能是下載檔案,這裡只要在瀏覽器輸入 url 就會下載那個檔案了。當時我只是簡單得使用 window.open ,但是卻會被瀏覽器進行攔截,要手動開啟才行,然後就搜尋研究其他方法,就看到各種各樣的,通過 js 開啟新視窗的方法了,這裡就總結一下

解決下載功能

這裡就先說解決下載功能的方法,通過同事的提醒,改用 iframe 進行處理,直接對 iframe 的 src 進行賦值,就會自動進行下載檔案了,不過,如果後端在 response header 設定了某個頭部,就會報錯了:x-frame-options: DENY

x-frame-options,是否允許 object 和 iframe 展示,有三個引數:

  • DENY: 即使是相同域名,也不能顯示
  • SAMEORIGIN: 可以在相同域名頁面展示
  • ALLOW-FROM uri: 任何來源都可以展示

MDN的解釋

我的後端同事在要下載的幾個介面中,把 x-frame-options 設定成 SAMEOPIGIN 後,前端就可以在無任何副作用的情況下,通過 js 進行下載檔案了

export: (url) => {
  // 移除舊的節點
  const oldNode = document.querySelector(`#g-exportOrder-iframe`)
  if (oldNode) {
    document.body.removeChild(document.querySelector(`#g-exportOrder-iframe`))
  }
  // 生成新節點,進行下載
  const iframe = document.createElement(`iframe`)
  iframe.style.display = "none"
  iframe.id = `g-exportOrder-iframe`
  iframe.src = url
  document.body.appendChild(iframe)
}

只要呼叫傳個 url ,就會自動下載一個檔案了

使用 window.open

如果我們是點選一個目標,然後同步執行開啟視窗操作,用 window.open 是可以的,但是我們把 window.open 放在非同步操作裡就有問題了

div.addEventListener(`click`, open, false)
function open() {
  setTimeout(() => {
    window.open(`/api/admin/adslot/all`)
  }, 1100)
}

我在谷歌、火狐和歐朋,這樣就會被攔截,然而用 ie9 卻不會被攔截,我給10秒,ie 最後還是會彈出來

從你用點選事件,到 window.open ,只要非同步操作超過某個時間,瀏覽器就會攔截這個彈窗的操作

如果不新增使用者的事件去觸發 window.open (比如點選事件,滑鼠移入移出等),而是在程式碼直接執行 window.open 的話,那樣瀏覽器也會攔截

window.onload = function() {
  windon.open()
}

總得來講,如果沒有用使用者操作的事件去觸發 window.open 就會被攔截,而把 window.open 放在非同步操作,且超過一定的事件,也會被攔截

這裡先想到了解決非同步也會被攔截的方法

var test = window.open()
setTimeout(function() {
  test.location = `http://www.xxx.com`
}, 2000)

在非同步操作前,先開啟視窗,然後再在你要操作的位置,更改這個視窗的 location ,不過這個缺陷有點大,要等非同步操作完成了,新的視窗才會從空白變到指定頁面,而且這種解決不了,沒有人為事件觸發 window.open 導致被攔截的問題

使用 a 標籤

這是最常見開啟一個新標籤頁面的方法

<a class=`test` href=`http://www.xxx.com` target=`_blank`></a>

然後,我點選另外一個 div ,再開啟新視窗

function open() {
  setTimeout(function() {
    document.querySelector(`.test`).click()
  }, 2000)
}

上面的非同步操作,還是不行,就算是重新生成一個 a 標籤,再用 click() 觸發也是不行

form submit

<form class=`test` target=`_blank` @click=`open` method=`GET` action=`http://www.xxx.com`>click me</form>
function open2() {
  setTimeout(() => {
    document.querySelector(`.test`).submit()
  }, 2000)
}

和 a 標籤一樣

DEMO 連結

總結

如果要下載檔案的話,使用 iframe

如果要開啟新視窗,而且沒有使用者操作的前提下開啟,是不能顯示的,只能提示讓使用者關閉那個攔截吧

有使用者操作,且是非同步的情況下,就使用 window.open ,然後定義 location 這樣就好了

相關文章