JavaScrip如果基于url實(shí)現(xiàn)圖片下載
1.H5 download屬性
function downFile(content, filename) { // 創(chuàng)建隱藏的可下載鏈接 var eleLink = document.createElement('a'); eleLink.download = filename; eleLink.style.display = 'none'; // 字符內(nèi)容轉(zhuǎn)變成blob地址 var blob = new Blob([content]); eleLink.href = URL.createObjectURL(blob); // 觸發(fā)點(diǎn)擊 document.body.appendChild(eleLink); eleLink.click(); // 然后移除 document.body.removeChild(eleLink); };
downFile(下載地址, 保存名稱(chēng));
2.iframe方式
// if (typeof(download.iframe) == 'undefined') { // var iframe = document.createElement('iframe'); // download.iframe = iframe; // document.body.appendChild(download.iframe); // }; // download.iframe.src = newdownloadUrl; // download.iframe.style.display = "none";
3.form方式
// var $eleForm = $("<form method='get'></form>"); // $eleForm.attr("action", "https://codeload.github.com/douban/douban-client/legacy.zip/master"); // $eleForm.attr("action", url); // $(document.body).append($eleForm); // $eleForm.submit();
downloadIamge(imgsrc, name) {//下載圖片地址和圖片名 let image = new Image(); // 解決跨域 Canvas 污染問(wèn)題 image.setAttribute("crossOrigin", "anonymous"); image.onload = function() { let canvas = document.createElement("canvas"); canvas.width = image.width; canvas.height = image.height; let context = canvas.getContext("2d"); context.drawImage(image, 0, 0, image.width, image.height); let url = canvas.toDataURL("image/png"); //得到圖片的base64編碼數(shù)據(jù) let a = document.createElement("a"); // 生成一個(gè)a元素 let event = new MouseEvent("click"); // 創(chuàng)建一個(gè)單擊事件 a.download = name || "photo"; // 設(shè)置圖片名稱(chēng) a.href = url; // 將生成的URL設(shè)置為a.href屬性 a.dispatchEvent(event); // 觸發(fā)a的單擊事件 }; image.src = imgsrc; },
原理
我們先看看 download 的使用方法:
<a href="http://somehost/somefile.zip" rel="external nofollow" rel="external nofollow" download="filename.zip">Download file</a>
看看上面的代碼,只要為 <a> 標(biāo)簽添加 download 屬性,我們點(diǎn)擊這個(gè)鏈接的時(shí)候就會(huì)自動(dòng)下載文件了~
順便說(shuō)下,download 的屬性值是可選的,它用來(lái)指定下載文件的文件名。像上面的例子中,我們下載到本地的文件名就會(huì)是 filename.zip 拉,如果不指定的話(huà),它就會(huì)是 somefile.zip 這個(gè)名字拉!
看到這里,你可能會(huì)說(shuō),坑爹啊,這明明是用 HTML 5 的新特性來(lái)實(shí)現(xiàn)下載文件嘛,說(shuō)好的用 JavaScript 下載文件呢?
事實(shí)上,用 JavaScript 來(lái)下載文件也是利用這一特性來(lái)實(shí)現(xiàn)的,我們的 JavaScript 代碼不外乎就是:
- 用 JavaScript 創(chuàng)建一個(gè)隱藏的 <a> 標(biāo)簽
- 設(shè)置它的 href 屬性
- 設(shè)置它的 download 屬性
- 用 JavaScript 來(lái)觸發(fā)這個(gè)它的 click 事件
翻譯成 JavaScript 代碼就是:
var a = document.createElement('a'); var url = window.URL.createObjectURL(blob); var filename = 'what-you-want.txt'; a.href = url; a.download = filename; a.click(); window.URL.revokeObjectURL(url);
好拉,是不是看到有個(gè)陌生的東東呢?
window.URL
window.URL 里面有兩個(gè)方法:
createObjectURL 用 blob 對(duì)象來(lái)創(chuàng)建一個(gè) object URL(它是一個(gè) DOMString),我們可以用這個(gè) object URL 來(lái)表示某個(gè) blob 對(duì)象,這個(gè) object URL 可以用在 href 和 src 之類(lèi)的屬性上。
revokeObjectURL 釋放由 createObjectURL 創(chuàng)建的 object URL,當(dāng)該 object URL 不需要的時(shí)候,我們要主動(dòng)調(diào)用這個(gè)方法來(lái)獲取最佳性能和內(nèi)存使用。
知道了這兩個(gè)方法之后,我們?cè)倩厝タ纯瓷厦娴睦泳秃苋菀桌斫饬税?!只是?blob 對(duì)象來(lái)創(chuàng)建一條 URL,然后讓 <a> 標(biāo)簽引用該 URL,然后觸發(fā)個(gè)點(diǎn)擊事件,就可以下載文件了!
那么問(wèn)題來(lái)了,blob 對(duì)象哪里來(lái)?
Blob 對(duì)象
Blob 全稱(chēng)是 Binary large object,它表示一個(gè)類(lèi)文件對(duì)象,可以用它來(lái)表示一個(gè)文件。根據(jù) MDN 上面的說(shuō)法,F(xiàn)ile API 也是基于 blob 來(lái)實(shí)現(xiàn)的。
由于本文的主題是講 JavaScript 下載文件,那我們構(gòu)建 blob 的方式就是通過(guò)服務(wù)器返回的文件來(lái)創(chuàng)建 blob 拉!
而最簡(jiǎn)單的方式就是用 fetch API 了,我們可以整合上面的例子:
fetch('http://somehost/somefile.zip').then(res => res.blob().then(blob => { var a = document.createElement('a'); var url = window.URL.createObjectURL(blob); var filename = 'myfile.zip'; a.href = url; a.download = filename; a.click(); window.URL.revokeObjectURL(url); }))
很簡(jiǎn)單對(duì)吧!
你可能會(huì)問(wèn),何必這么麻煩呢?直接寫(xiě)成下面這樣不就好了:
<a href="http://somehost/somefile.zip" rel="external nofollow" rel="external nofollow" download="myfile.zip">Download file</a>
嗯,對(duì)于這種寫(xiě)法,我只能說(shuō),你做的太正確了!如果你要下載的是已經(jīng)存在服務(wù)器上面的靜態(tài)文件的話(huà),那么寫(xiě)成這樣是最方便的。瀏覽器會(huì)幫你處理整個(gè)下載過(guò)程,不需要你干涉。如果你用 blob 的方式來(lái)下載文件的話(huà),會(huì)有下面這些限制的:
限制一:不同瀏覽器對(duì) blob 對(duì)象有不同的限制
具體看看下面這個(gè)表格(出自 FileSaver.js):
Browser | Constructs as | Filenames | Max Blob Size | Dependencies |
---|---|---|---|---|
Firefox 20+ | Blob | Yes | 800 MiB | None |
Firefox < 20 | data: URI | No | n/a | Blob.js |
Chrome | Blob | Yes | 500 MiB | None |
Chrome for Android | Blob | Yes | 500 MiB | None |
Edge | Blob | Yes | ? | None |
IE 10+ | Blob | Yes | 600 MiB | None |
Opera 15+ | Blob | Yes | 500 MiB | None |
Opera < 15 | data: URI | No | n/a | Blob.js |
Safari 6.1+* | Blob | No | ? | None |
Safari < 6 | data: URI | No | n/a | Blob.js |
限制二:構(gòu)建完 blob 對(duì)象后才會(huì)轉(zhuǎn)換成文件
這一點(diǎn)限制對(duì)小文件(幾十kb)可能沒(méi)什么影響,但對(duì)稍微大一點(diǎn)的文件影響就很大了。試想,用戶(hù)要下載一個(gè) 100mb 的文件,如
果他點(diǎn)擊了下載按鈕之后沒(méi)看到下載提示的話(huà),他肯定會(huì)繼續(xù)按,等他按了幾次之后還沒(méi)看到下載提示時(shí),他就會(huì)抱怨我們的網(wǎng)站,然后離開(kāi)了。
然而事實(shí)上下載的的確確發(fā)生了,只是要等到下載完文件之后才能構(gòu)建 blob 對(duì)象,再轉(zhuǎn)化成文件。而且,用戶(hù)再觸發(fā)多幾次下載就會(huì)造成一些資源上的浪費(fèi)。
因此,如果是要下載大文件的話(huà),還是推薦直接創(chuàng)建一個(gè) <a> 標(biāo)簽拉~
寫(xiě) html 也好,寫(xiě) JavaScript 動(dòng)態(tài)創(chuàng)建也好,用自己喜歡的方式去創(chuàng)建就好了。
為什么要用 JavaScript 下載文件
好拉,說(shuō)了半天,其實(shí)我們一直說(shuō)的都是:「不要用 JavaScript 下載文件拉,限制多多,又不好用,直接用 html 就好拉,簡(jiǎn)單方便又快捷」這個(gè)論調(diào)。
事實(shí)上也確實(shí)如此,但有些時(shí)候我們確實(shí)需要通過(guò) JavaScript 來(lái)做一些預(yù)處理。
權(quán)限校驗(yàn)
有些時(shí)候,我們需要對(duì)下載做一些限制,最常見(jiàn)的就是權(quán)限校驗(yàn)了,如檢查該用戶(hù)是否有下載的權(quán)限,是否有高速下載的權(quán)限等等。這時(shí)候,我們可以利用 JavaScript 做一些預(yù)處理。如:
fetch('http://somehost/check-permission', options).then(res => { if (res.code === 0) { var a = document.createElement('a'); var url = res.data.url; var filename = 'myfile.zip'; a.href = url; a.download = filename; a.click(); } else { alert('You have no permission to download the file!'); } });
在這個(gè)例子里面,我們沒(méi)有用 blob 來(lái)構(gòu)建 URL,而是通過(guò)后端服務(wù)器來(lái)計(jì)算出用戶(hù)的下載鏈接,然后再利用之前提到的動(dòng)態(tài)創(chuàng)建 <a> 標(biāo)簽的方式來(lái)實(shí)現(xiàn)下載,很簡(jiǎn)單吧!
動(dòng)態(tài)文件
動(dòng)態(tài)生成文件然后返回給客戶(hù)端也是一個(gè)很常見(jiàn)的需求,譬如我們有時(shí)候需要做導(dǎo)出數(shù)據(jù)的功能,把數(shù)據(jù)庫(kù)中的某些數(shù)據(jù)導(dǎo)出到 Excel 中,然后再返回客戶(hù)端。
這時(shí)候我們就不能簡(jiǎn)單的指定 href 屬性,因?yàn)閷?duì)應(yīng)的 URL 并不存在。
我們只能通過(guò) JavaScript 對(duì)服務(wù)器發(fā)出一個(gè)請(qǐng)求,通知它去生成某個(gè)文件,然后把對(duì)應(yīng)的 URL 返回給客戶(hù)端。
有沒(méi)有感覺(jué)這個(gè)過(guò)程和上面「權(quán)限校驗(yàn)」一節(jié)很像?肯定拉,因?yàn)槲覀冎皇菍?duì) URL 做了一些預(yù)處理而已嘛~
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
echarts餅圖各個(gè)板塊之間的空隙如何實(shí)現(xiàn)
這篇文章主要給大家介紹了關(guān)于echarts餅圖各個(gè)板塊之間的空隙如何實(shí)現(xiàn)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12javascript作用域鏈與執(zhí)行環(huán)境詳解
這篇文章主要為大家詳細(xì)介紹了javascript作用域鏈與執(zhí)行環(huán)境,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03基于js?+?html2canvas實(shí)現(xiàn)網(wǎng)頁(yè)放大鏡功能
最近接到任務(wù),需實(shí)現(xiàn)【網(wǎng)頁(yè)】放大鏡的效果,百度搜索?【js?放大鏡】關(guān)鍵字,千篇一律的都是一些仿淘寶/京東等電商網(wǎng)站中查看規(guī)格大圖的效果實(shí)現(xiàn),根本無(wú)法滿(mǎn)足我的需求,于是自己花了點(diǎn)時(shí)間調(diào)研實(shí)現(xiàn),在這里分享給大家,感興趣的朋友可以參考下2023-12-12js中一個(gè)函數(shù)獲取另一個(gè)函數(shù)返回值問(wèn)題探討
在本文將為大家詳細(xì)探討下js中一個(gè)函數(shù)獲取另一個(gè)函數(shù)返回值問(wèn)題,比較模糊的朋友可以學(xué)習(xí)下哦2013-11-11JavaScript中實(shí)現(xiàn)Map的示例代碼
本篇文章給大家介紹javascript中實(shí)現(xiàn)map的示例代碼,代碼寫(xiě)的簡(jiǎn)單易懂,可以獲取、刪除鍵值,剛興趣的朋友跟著腳本之家小編一起學(xué)習(xí)吧。2015-09-09JavaScript實(shí)現(xiàn)非常簡(jiǎn)單實(shí)用的下拉菜單效果
這篇文章主要介紹了JavaScript實(shí)現(xiàn)非常簡(jiǎn)單實(shí)用的下拉菜單效果,通過(guò)定義顯示及隱藏菜單項(xiàng)及鼠標(biāo)事件調(diào)用該函數(shù)實(shí)現(xiàn)下拉菜單功能,需要的朋友可以參考下2015-08-08