之前的專案,有個功能是下載檔案,這裡只要在瀏覽器輸入 url 就會下載那個檔案了。當時我只是簡單得使用
window.open
,但是卻會被瀏覽器進行攔截,要手動開啟才行,然後就搜尋研究其他方法,就看到各種各樣的,通過 js 開啟新視窗的方法了,這裡就總結一下
解決下載功能
這裡就先說解決下載功能的方法,通過同事的提醒,改用 iframe 進行處理,直接對 iframe 的 src 進行賦值,就會自動進行下載檔案了,不過,如果後端在 response header 設定了某個頭部,就會報錯了:x-frame-options: DENY
x-frame-options,是否允許 object 和 iframe 展示,有三個引數:
- DENY: 即使是相同域名,也不能顯示
- SAMEORIGIN: 可以在相同域名頁面展示
- ALLOW-FROM uri: 任何來源都可以展示
我的後端同事在要下載的幾個介面中,把 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 標籤一樣
總結
如果要下載檔案的話,使用 iframe
如果要開啟新視窗,而且沒有使用者操作的前提下開啟,是不能顯示的,只能提示讓使用者關閉那個攔截吧
有使用者操作,且是非同步的情況下,就使用 window.open
,然後定義 location
這樣就好了