JavaScript tips —— 關於下載與導出的二三事

前言

在項目中常常會遇到下載或導出服務端資源的需求,通常分爲2種作法
  1. 獲取文件流,編碼後下載
  2. 獲取文件的url,直接下載
本文主要探討第二種方法,在最後會說起文件流的方法。


瀏覽器的安全策略

在介紹方法以前,咱們須要知道瀏覽器的一些安全機制,防止惡意代碼對用戶的破壞。
現代瀏覽器(ie8除外)檢測到非用戶直接操做產生的新窗口,通常會阻止,好比在ajax的回調中打開新的窗口,由於這些操做並非在用戶點擊的線程中,因此會攔截。


預開新標籤頁

作法

  1. 在異步操做以前,先打開一個新標籤頁
  2. 請求後端資源的地址
  3. 獲取url後去修改空白頁的url
const downloadTab = window.open('about:blank');

ajax.get('xxx').then(url => {
    // 使用後端資源的url進行下載
    downloadTab.location.href = href;
}).catch(err => {
    // 處理異常
    downloadTab.close();
})

複製代碼

缺點

  1. 無論請求成功仍是失敗都會有新頁面的閃爍出現
  2. 打開的新頁面在何時關閉是個問題,由於若是請求時間過長,用戶可能本身關閉新頁面,更很差處理的狀況是頁面何時觸發了下載,由於若是隻是更改url就關閉窗口可能尚未開始下載的操做。


生成iframe

作法

爲了不頁面閃爍與關閉時機的問題,能夠在當前頁面使用動態建立iframe的方式,直接下載
ajax.get('xxx').then(href => {
    if (!href) {
      return;
    }

    if (!this.downIframe) {
      this.downIframe = document.createElement('iframe'); // 動態建立iframe
      this.downIframe.src = href; // iframe 中加載的頁面
      this.downIframe.id = 'downloadIframe'; // iframe 中加載的頁面
      this.downIframe.style.width = '1px';
      this.downIframe.style.height = '1px';
      this.downIframe.style.position = 'absolute';
      this.downIframe.style.left = '-100px';
      document.body.appendChild(this.downIframe); // 添加到當前窗體
    } else {
      this.downIframe.src = href; // iframe 中加載的頁面
    }
}).catch(err => {
    // 處理異常
})
複製代碼

缺點

雖然能夠優雅的下載文件了,但是若是須要定製下載文件的名稱就會使人頭疼了,咱們須要時機去改變下載文件的名稱,不然就會使服務端的文件名稱。


生成標籤

利用download屬性設置文件名,
ajax.get('xxx').then(href => {
    if (!href) {
      return;
    }

    var a = document.createElement('a');
    var url = href;
    var filename = 'test.zip';
    a.href = url;
    a.download = filename; // 在沒有download屬性的狀況,target="_blank",仍會阻止打開
    a.click();
}).catch(err => {
    // 處理異常
})
複製代碼
注意:
有些瀏覽器須要將a標籤嵌入頁面纔可執行。


處理文件流

最後大概講一下若是後端返回流怎麼處理。
function funDownload(content, filename) {
    // 建立隱藏的可下載連接
    var link = document.createElement('a');
    link.download = filename;
    link.style.display = 'none';

    // 字符內容轉變成blob地址
    var blob = new Blob([content]);
    //若是是excel格式
    //var blob = new Blob([content], {type: 'application/vnd.ms-excel'}),
    link.href = URL.createObjectURL(blob);

    // 觸發點擊
    document.body.appendChild(link);
    link.click();
    // 而後移除
    document.body.removeChild(link);
};
複製代碼
URL.createObjectURL() 靜態方法會建立一個 DOMString,其中包含一個表示參數中給出的對象的URL。這個 URL 的生命週期和建立它的窗口中的 document 綁定。這個新的URL 對象表示指定的 File 對象或 Blob 對象。


注意:
在每次調用 createObjectURL() 方法時,都會建立一個新的 URL 對象,即便你已經用相同的對象做爲參數建立過。當再也不須要這些 URL 對象時,每一個對象必須經過調用 URL.revokeObjectURL() 方法來釋放。瀏覽器會在文檔退出的時候自動釋放它們,可是爲了得到最佳性能和內存使用情況,你應該在安全的時機主動釋放掉它們。
相關文章
相關標籤/搜索