成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

前端js實(shí)現(xiàn)字符串/圖片/excel文件下載

ingood / 1045人閱讀

摘要:實(shí)現(xiàn)并發(fā)請(qǐng)求實(shí)現(xiàn)并發(fā)請(qǐng)求生成并下載字符串文件首先我們需要了解一個(gè)特殊的數(shù)據(jù)格式。如果類型未知,則該值為空字符串。表示狀態(tài)的數(shù)字。一旦完成,屬性中將包含一個(gè)字符串以表示所讀取的文件內(nèi)容。

web開(kāi)發(fā)中,如果你想讓用戶下載或者導(dǎo)出一個(gè)文件,應(yīng)該怎么做呢?
傳統(tǒng)的做法是在后端存儲(chǔ)或者即時(shí)生成一個(gè)文件來(lái)提供下載功能,這樣的優(yōu)勢(shì)是可以做權(quán)限控制、數(shù)據(jù)二次處理,但缺點(diǎn)是需要額外發(fā)起請(qǐng)求、增大服務(wù)端壓力、下載速度慢。

但隨著HTML5的標(biāo)準(zhǔn)發(fā)布,我們已經(jīng)能夠做到只前端來(lái)下載各種文件了。

后端響應(yīng)式下載
在常規(guī)的HTTP應(yīng)答中,Content-Disposition 消息頭指示回復(fù)的內(nèi)容該以何種形式展示,是以內(nèi)聯(lián)的形式(即網(wǎng)頁(yè)或者頁(yè)面的一部分),還是以附件的形式下載并保存到本地。

HTTP場(chǎng)景中,第一個(gè)參數(shù)或者是inline(默認(rèn)值,表示回復(fù)中的消息體會(huì)以頁(yè)面的一部分或者整個(gè)頁(yè)面的形式展示),或者是attachment(意味著消息體應(yīng)該被下載到本地;大多數(shù)瀏覽器會(huì)呈現(xiàn)一個(gè)“保存為”的對(duì)話框,將filename的值預(yù)填為下載后的文件名)。

我們?cè)诤蠖隧憫?yīng)頭中只要設(shè)置該頭部信息,即可下載為文件,而不是請(qǐng)求并展示:

Content-Type: text/html; charset=utf-8
Content-Disposition: attachment; filename="cool.html"

但需要注意的是,如果想要用這種方式下載文件,不能使用AJAX的方式,而是應(yīng)該新建一個(gè)標(biāo)簽,模擬點(diǎn)擊下載。原因?yàn)樘幱诎踩钥紤],JavaScript無(wú)法與磁盤(pán)進(jìn)行交互,因此AJAX得到的內(nèi)容將被保留在內(nèi)存中,而不是磁盤(pán)上。

Nginx添加header頭下載
location ~ .(jpg|jpeg|png|bmp|ico|gif|swf)$ {
    add_header Content-Disposition "attachment; filename="cool.html"";
}

和后端一樣的原理,只不過(guò)頭部信息通過(guò)Nginx統(tǒng)一添加。

前端下載:
標(biāo)簽的download屬性
此屬性指示瀏覽器下載URL而不是導(dǎo)航到它,因此將提示用戶將其保存為本地文件。如果屬性有一個(gè)值,那么它將作為下載的文件名使用。此屬性對(duì)允許的值沒(méi)有限制,但是/會(huì)被轉(zhuǎn)換為下劃線。

此屬性僅適用于同源 URLs。

盡管HTTP URL需要位于同一源中,但是可以使用 blob: URLsdata: URLs ,以方便用戶下載 JavaScript 方式生成的內(nèi)容(例如使用在線繪圖的Web應(yīng)用創(chuàng)建的照片)。

常規(guī)的標(biāo)簽,用于鏈接的跳轉(zhuǎn),如新的頁(yè)面,那么如果我們給標(biāo)簽加上download屬性,就能很簡(jiǎn)單的讓用戶保存新的html頁(yè)面。

PHP實(shí)現(xiàn)并發(fā)請(qǐng)求
生成并下載字符串文件

首先我們需要了解一個(gè)特殊的數(shù)據(jù)格式:Blob

Blob數(shù)據(jù)

Blob(Binary Large Object,二進(jìn)制類型的大對(duì)象),表示一個(gè)不可變的原始數(shù)據(jù)的類文件對(duì)象,我們上傳文件時(shí)常用的File對(duì)象就繼承于Blob,并進(jìn)行了擴(kuò)展用于支持用戶系統(tǒng)上的文件。

我們只能通過(guò)Blob()構(gòu)造函數(shù)來(lái)創(chuàng)建一個(gè)新的Blob對(duì)象:

Blob(blobParts[, options])
// 創(chuàng)建一個(gè)json類型的Blob對(duì)象,支持傳入同類型數(shù)據(jù)的一個(gè)數(shù)組
var debug = {hello: "world"};
var blob = new Blob([JSON.stringify(debug, null, 2)],
  {type : "application/json"});

// 此時(shí)blob的值
// Blob(22) {size: 22, type: "application/json"}

Blob對(duì)象存在兩個(gè)只讀屬性:

size: Blob 對(duì)象中所包含數(shù)據(jù)的大小(字節(jié))。
type: 一個(gè)字符串,表明該Blob對(duì)象所包含數(shù)據(jù)的MIME類型。如果類型未知,則該值為空字符串。
URL對(duì)象和下載字符串文件

URL 接口是一個(gè)用來(lái)創(chuàng)建 URLs 的對(duì)象,包含兩個(gè)靜態(tài)方法:

objectURL = URL.createObjectURL(blob)
創(chuàng)建一個(gè) URL(DOMString),包含一個(gè)唯一的blob鏈接(該鏈接協(xié)議為以blob:,后跟唯一標(biāo)識(shí)瀏覽器中的對(duì)象的掩碼)。這個(gè) URL 的生命周期和創(chuàng)建它的窗口中的 document 綁定。

URL.revokeObjectURL(objectURL)
銷毀之前使用URL.createObjectURL()方法創(chuàng)建的URL實(shí)例。瀏覽器會(huì)在文檔退出的時(shí)候自動(dòng)釋放它們,但是為了獲得最佳性能和內(nèi)存使用狀況,你應(yīng)該在安全的時(shí)機(jī)主動(dòng)釋放掉它們。

var url = URL.createObjectURL(blob);
// 此時(shí)url的值,跟document綁定,所以每個(gè)頁(yè)面創(chuàng)建的字符串均不同
// blob:https://developer.mozilla.org/defe53c2-2882-43c6-b275-db2a57959789

此時(shí),我們?cè)陧?yè)面中創(chuàng)建一個(gè)新標(biāo)簽,點(diǎn)擊即可下載我們想要的文件:

下載文件鏈接
FileReader讀取Blob數(shù)據(jù)

想要讀取Blob數(shù)據(jù)的唯一方法是FileReader。

FileReader 對(duì)象允許Web應(yīng)用程序異步讀取存儲(chǔ)在用戶計(jì)算機(jī)上的文件(或原始數(shù)據(jù)緩沖區(qū))的內(nèi)容,使用 FileBlob 對(duì)象指定要讀取的文件或數(shù)據(jù)。

其中File對(duì)象可以是來(lái)自用戶在一個(gè)元素上選擇文件后返回的FileList對(duì)象,也可以來(lái)自拖放操作生成的 DataTransfer對(duì)象,還可以是來(lái)自在一個(gè)HTMLCanvasElement上執(zhí)行mozGetAsFile()方法后返回結(jié)果。

該對(duì)象包含3個(gè)屬性:

FileReader.error
一個(gè)DOMException,表示在讀取文件時(shí)發(fā)生的錯(cuò)誤 。

FileReader.readyState
表示FileReader狀態(tài)的數(shù)字。取值如下:

常量名    值    描述
EMPTY    0    還沒(méi)有加載任何數(shù)據(jù).
LOADING    1    數(shù)據(jù)正在被加載.
DONE    2    已完成全部的讀取請(qǐng)求.

FileReader.result
文件的內(nèi)容。該屬性僅在讀取操作完成后才有效,數(shù)據(jù)的格式取決于使用哪個(gè)方法來(lái)啟動(dòng)讀取操作。

包含6個(gè)事件處理:onabort,onerror,onload,onloadstart,onloadend,onprogress,這些不再詳細(xì)說(shuō)明,因?yàn)?FileReader 繼承自EventTarget,所以所有這些事件也可以通過(guò)addEventListener方法使用。

包含5個(gè)方法:

FileReader.abort()
中止讀取操作。在返回時(shí),readyState屬性為DONE。

FileReader.readAsArrayBuffer()
開(kāi)始讀取指定的 Blob中的內(nèi)容, 一旦完成, result 屬性中保存的將是被讀取文件的 ArrayBuffer 數(shù)據(jù)對(duì)象.

FileReader.readAsBinaryString()
開(kāi)始讀取指定的Blob中的內(nèi)容。一旦完成,result屬性中將包含所讀取文件的原始二進(jìn)制數(shù)據(jù)。

FileReader.readAsDataURL()
開(kāi)始讀取指定的Blob中的內(nèi)容。一旦完成,result屬性中將包含一個(gè)data: URL格式的字符串以表示所讀取文件的內(nèi)容。

FileReader.readAsText()
開(kāi)始讀取指定的Blob中的內(nèi)容。一旦完成,result屬性中將包含一個(gè)字符串以表示所讀取的文件內(nèi)容。

因此我們可以直接讀取Blob對(duì)象的數(shù)據(jù):

var reader = new FileReader();
reader.addEventListener("loadend", function() {
   console.log(reader.result);
});
reader.readAsDataURL(blob);
// 此時(shí)result的值
// data:application/json;base64,ewogICJoZWxsbyI6ICJ3b3JsZCIKfQ==
reader.readAsText(blob);
// 此時(shí)result的值
// {
//     "hello": "world"
// }
下載圖片

除了下載手動(dòng)生成的字符串或?qū)ο?,我們還能提供下載圖片的功能,一方面能用于支持Canvas繪圖的保存功能,一方面能提供批量下載圖片等高級(jí)功能。

除了瀏覽器自帶的右鍵保存,我們還可以這么做來(lái)下載圖片:

// 通過(guò)src獲取圖片的blob對(duì)象
function getImageBlob(url, cb) {
    var xhr = new XMLHttpRequest();
    xhr.open("get", url, true);
    xhr.responseType = "blob";
    xhr.onload = function() {
        if (this.status == 200) {
            cb(this.response);
        }
    };
    xhr.send();
}

let reader = new FileReader();
reader.addEventListener("loadend", function() {
   console.log(reader.result);
});
getImageBlob("https://cdn.segmentfault.com/v-5c4ec07f/global/img/user-64.png", function(blob){
    // 讀取來(lái)看下下載的內(nèi)容
    reader.readAsDataURL(blob);
    // 最終生成的字符串
    // data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAA...
    // 生成下載用的URL對(duì)象
    let url = URL.createObjectURL(blob);
    // 生成一個(gè)a標(biāo)簽,并模擬點(diǎn)擊,即可下載,批量下載同理
    let aDom = aDom = document.createElement("a");
    aDom.href = url;
    aDom.download = "download.json";
    aDom.text = "下載文件";
    document.getElementsByTagName("body")[0].appendChild(aDom);
    aDom.click();
});
下載excel文件等

如果你明白了下載的原理,那么所有的內(nèi)容都能夠理解,只不過(guò)是轉(zhuǎn)換成對(duì)應(yīng)的格式而已,當(dāng)然,復(fù)雜格式的文檔不需要你自己去配置,可以引入第三方庫(kù),在excel文檔方面我選擇用 tableExport庫(kù):

// 引入CDN文件
"https://cdn.bootcss.com/xlsx/0.14.1/xlsx.core.min.js",
"https://cdn.bootcss.com/FileSaver.js/2014-11-29/FileSaver.min.js",
"https://cdn.bootcss.com/TableExport/5.2.0/js/tableexport.min.js"

// 綁定下載事件,這個(gè)是我自己的場(chǎng)景下代碼,可能不適合大家,具體的參考官方文檔
const tableDom = $("#table");
$(".table-exportBtn", tableDom).on("click", function () {
    const tableExport = tableDom.tableExport({
        formats: ["xlsx", "txt"],
        filename: "表格下載",
        exportButtons: false
    });
    const type = $(this).data().type;
    const exportData = tableExport.getExportData()[tableDom[0].id][type];
    const {data, mimeType, filename, fileExtension, merges, RTL, sheetname} = exportData;
    // 源碼里才能看到完整參數(shù),官方文檔沒(méi)有寫(xiě)全,導(dǎo)致下載的文件格式錯(cuò)誤
    tableExport.export2file(data, mimeType, filename, fileExtension, merges, RTL, sheetname);
});

默認(rèn)的方法會(huì)自動(dòng)生成下載按鈕,但如果你想自定義下載功能,參考 exportButtons: false 設(shè)置 一節(jié),但這個(gè)文檔有問(wèn)題,export2file參數(shù)不完整,導(dǎo)致下載的xlsx文件一直格式錯(cuò)誤,通過(guò)查看源碼,需要寫(xiě)全參數(shù)才可以,上面的示例里已經(jīng)寫(xiě)出。

tableExport庫(kù)源碼

我們可以看下tableExport導(dǎo)出文件的核心代碼,其導(dǎo)出為excel格式比較復(fù)雜,由xlsx.core.min.js來(lái)完成:

/**
     * Exports and downloads the file
     * @memberof TableExport.prototype
     * @param data {String}
     * @param mime {String} mime type
     * @param name {String} filename
     * @param extension {String} file extension
     * @param merges {Object[]}
     * @param RTL {Boolean}
     */
    export2file: function(data, mime, name, extension, merges, RTL, sheetname) {
      var format = extension.slice(1);
      data = this.getRawData(data, extension, name, merges, RTL, sheetname);

      if (_isMobile && (format === _FORMAT.CSV || format === _FORMAT.TXT)) {
        // 拼湊指定格式的data:類型 URI
        var dataURI = "data:" + mime + ";" + this.charset + "," + data;
        this.downloadDataURI(dataURI, name, extension);
      } else {
        // TODO: error and fallback when `saveAs` not available
        saveAs(new Blob([data], { type: mime + ";" + this.charset }), name + extension, true);
      }
    },
    // 先創(chuàng)建標(biāo)簽,然后提供href和download屬性,并模擬點(diǎn)擊
    downloadDataURI: function(dataURI, name, extension) {
      var encodedUri = encodeURI(dataURI);
      var link = document.createElement("a");
      link.setAttribute("href", encodedUri);
      link.setAttribute("download", name + extension);
      document.body.appendChild(link);
      link.click();
    },
xlsx文件導(dǎo)出導(dǎo)出

還沒(méi)有仔細(xì)研究,感興趣的可以查看其js-xlsx Github項(xiàng)目

第三方庫(kù)

上面我們主要講了下載背后的原理,你可以自己封裝,也可以使用現(xiàn)成的第三方庫(kù),如 download.js ,這個(gè)能提供大部分常用數(shù)據(jù)的下載;但如果你是要下載表格數(shù)據(jù)為excel格式,還是推薦 tableExport.js 及其依賴組件。

參考資料

MDN-a: https://developer.mozilla.org...

MDN-blob: https://developer.mozilla.org...

掘金-細(xì)說(shuō)Web API中的Blob:https://juejin.im/post/59e35d...

MDN-URL: https://developer.mozilla.org...

MDN-FileReader: https://developer.mozilla.org...

博客園-js 獲取圖片url的Blob值并預(yù)覽:https://www.cnblogs.com/tujia...

tableExport文檔:https://tableexport.v5.travis...

感謝 @Oliveryoung 提供的其他解決方案

MDN-Content-Disposition: https://developer.mozilla.org...

Ajax請(qǐng)求無(wú)法下載文件的原因: https://blog.csdn.net/w405722...

Github-download.js: https://github.com/rndme/down...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/40336.html

相關(guān)文章

  • 前端js實(shí)現(xiàn)符串/圖片/excel文件下載

    摘要:實(shí)現(xiàn)并發(fā)請(qǐng)求實(shí)現(xiàn)并發(fā)請(qǐng)求生成并下載字符串文件首先我們需要了解一個(gè)特殊的數(shù)據(jù)格式。如果類型未知,則該值為空字符串。表示狀態(tài)的數(shù)字。一旦完成,屬性中將包含一個(gè)字符串以表示所讀取的文件內(nèi)容。 在web開(kāi)發(fā)中,如果你想讓用戶下載或者導(dǎo)出一個(gè)文件,應(yīng)該怎么做呢?傳統(tǒng)的做法是在后端存儲(chǔ)或者即時(shí)生成一個(gè)文件來(lái)提供下載功能,這樣的優(yōu)勢(shì)是可以做權(quán)限控制、數(shù)據(jù)二次處理,但缺點(diǎn)是需要額外發(fā)起請(qǐng)求、增大服務(wù)端...

    DevWiki 評(píng)論0 收藏0
  • js】——前端無(wú)插件導(dǎo)出excel:自定義sheet、插入圖片、設(shè)置打印、頁(yè)邊距、頁(yè)腳等

    摘要:思路用現(xiàn)有的導(dǎo)出的插件,無(wú)法實(shí)現(xiàn),所以只能手寫(xiě)各種樣式代碼關(guān)于打印頁(yè)腳之類無(wú)從下手的要求,需要導(dǎo)出后,復(fù)制一份,原文件拖進(jìn),查看源碼,復(fù)制的那份用打開(kāi),設(shè)置打印頁(yè)腳。 背景 前段時(shí)間因一個(gè)需求后端無(wú)法完成,所以交給前端來(lái)實(shí)現(xiàn),導(dǎo)出表格,需要實(shí)現(xiàn):1、支持多個(gè)sheet,并且有自己的name2、根據(jù)要求合并單元格,設(shè)置單元格的寬高3、在表格內(nèi)有各自的二維碼4、打印的頁(yè)邊距為左右各0.5c...

    flybywind 評(píng)論0 收藏0
  • [SheetJS] js-xlsx模塊學(xué)習(xí)指南

    摘要:簡(jiǎn)介是前端操作以及類似的二維表的最佳選擇之一而是它的社區(qū)版本將注意力集中到了數(shù)據(jù)轉(zhuǎn)換和導(dǎo)出上所以它支持相當(dāng)多種類的數(shù)據(jù)解析和導(dǎo)出不僅僅局限于支持格式支持的導(dǎo)入格式支持的導(dǎo)出格式它可以解析符合格式的數(shù)據(jù)導(dǎo)出符合格式的數(shù)據(jù)利用中間層操作數(shù)據(jù) 簡(jiǎn)介 SheetJS是前端操作Excel以及類似的二維表的最佳選擇之一,而js-xlsx是它的社區(qū)版本. js-xlsx將注意力集中到了數(shù)據(jù)轉(zhuǎn)換和導(dǎo)出...

    zhaot 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<