需求
有一個H5頁面,頁面中有個“點擊下載”的按鈕,點擊之后,完成下載特定的apk或者txt等其他類型文件(微信好坑,各種限制,基本上從微信瀏覽器里面實現直接下載apk是不太可能的)
方法一:download屬性
首先看下面這種截圖:
如果我們想實現點擊上面的下載按鈕下載一張圖片,你會如何實現?
我們可能會想到一個最簡單的方法,就是直接按鈕a
標簽鏈接一張圖片,類似下面這樣:
<a href="large.jpg">下載</a>
但是,想法雖好,實際效果卻不是我們想要的,因為瀏覽器可以直接瀏覽圖片,因此,我們點擊下面的“下載”鏈接,並是不下載圖片,而是在新窗口直接瀏覽圖片。
我們希望點擊“下載”鏈接下載圖片而不是瀏覽,直接增加一個download
屬性就可以:
<a href="large.jpg" download>下載</a>
不僅如此,我們還可以指定下載圖片的文件名:
<a href="index_logo.gif" download="_5332_.gif">下載</a>
如果后綴名一樣,我們還可以缺省,直接文件名:
<a href="index_logo.gif" download="_5332_">下載</a>
瀏覽器兼容性和跨域策略
如果需要下載的資源是跨域的,包括跨子域,在Chrome瀏覽器下,使用download
屬性是可以下載的,但是,並不能重置下載的文件的命名;而FireFox瀏覽器下,則download
屬性是無效的,也就是FireFox瀏覽器無論如何都不支持跨域
資源的download
屬性下載。而,如果資源是同域名的,則兩個瀏覽器都是暢通無阻的下載,不會出現下載變瀏覽的情況。
是否支持download屬性的監測
要監測當前瀏覽器是否支持download
屬性,一行JS代碼就可以了,如下:
var isSupportDownload = 'download' in document.createElement('a');
使用總結
1、在微信中無法使用download屬性
2、兼容性不好,在chrome上嘗試並沒有下載
方法二:window.location.href
window.location.href = 'http://imtt.dd.qq.com/16891/26747DD8B125A8479AD0C9D22CA47BC9.apk?fsname=com.snda.wifilocating_4.2.91_3211.apk&csr=1bbd';
點擊下載按鈕的時候改變location.href,拿在瀏覽器里面試了下,多個安卓機型都可以走通,但會出現空白頁,空白頁是因為改變href為apk的下載鏈接,網頁打開的時候會停留在一個空白頁,然后一般手機的狀態欄上會出現下載apk的進
度條。既然不想出現空白頁面的話,那不直接打開一個頁面而改成在當前頁打開就可以了。( 遇到的空白頁是因為有的手機下載的時候其實是跳轉到這個apk的地址,在那等着apk下載完成,這個等待的頁面就是個空白頁面了)
方法三:借助iframe
var src = 'http://imtt.dd.qq.com/16891/26747DD8B125A8479AD0C9D22CA47BC9.apk?fsname=com.snda.wifilocating_4.2.91_3211.apk&csr=1bbd'; var iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = "javascript: '<script>location.href=\"" + src + "\"<\/script>'"; document.getElementsByTagName('body')[0].appendChild(iframe);
使用iframe的話,既可以實現下載,又可以不重新打開頁面,並且,對原頁面的布局不會產生任何影響。
方法四:借助form
var src = 'http://imtt.dd.qq.com/16891/26747DD8B125A8479AD0C9D22CA47BC9.apk?fsname=com.snda.wifilocating_4.2.91_3211.apk&csr=1bbd'; var form = document.createElement('form'); form.action = src; document.getElementsByTagName('body')[0].appendChild(form); form.submit();
既然使用iframe可以,那使用form一定也是可以的,form的action也可以發請求。
方法五:借助HTML5 Blob實現文本信息文件下載 【親測好用】
原理其實很簡單,我們可以將文本或者JS字符串信息借助Blob轉換成二進制,然后,作為<a>
元素的href
屬性,配合download
屬性,實現下載。
代碼也比較簡單,如下示意(兼容Chrome和Firefox):
var funDownload = function (content, filename) { // 創建隱藏的可下載鏈接 var eleLink = document.createElement('a'); eleLink.download = filename; eleLink.style.display = 'none'; // 字符內容轉變成blob地址 var blob = new Blob([content]);
// 簡單的理解一下就是將一個file
或Blob
類型的對象轉為UTF-16
的字符串,並保存在當前操作的document eleLink.href = URL.createObjectURL(blob); // 觸發點擊 document.body.appendChild(eleLink); eleLink.click(); // 然后移除 document.body.removeChild(eleLink); };
其中,content
指需要下載的文本或字符串內容,filename
指下載到系統中的文件名稱。
實例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script> window.onload = function() { var eleTextarea = document.querySelector('textarea'); var eleButton = document.querySelector('input[type="button"]'); // 下載文件方法 var funDownload = function (content, filename) { var eleLink = document.createElement('a'); eleLink.download = filename; eleLink.style.display = 'none'; // 字符內容轉變成blob地址 var blob = new Blob([content]); eleLink.href = URL.createObjectURL(blob); // 觸發點擊 document.body.appendChild(eleLink); eleLink.click(); // 然后移除 document.body.removeChild(eleLink); }; if ('download' in document.createElement('a')) { // 作為test.html文件下載 eleButton.addEventListener('click', function () { funDownload(eleTextarea.value, 'test.html'); }); } else { eleButton.onclick = function () { alert('瀏覽器不支持'); }; } } </script> </head> <body> <textarea rows="11"> </textarea> <p><input type="button" value="作為test.html文件下載"></p> </body> </html>
點擊“下載”按鈕,會把文本域中的內容全部作為一個.html
后綴文件下載下來,各流程效果如下面幾張圖:
觸發下載的JS代碼就幾行:
button.addEventListener('click', function () { funDownload(textarea.value, 'test.html'); });
方法六:借助Base64實現任意文件下載
對於非文本文件,也是可以直接JS觸發下載的,例如,如果我們想下載一張圖片,可以把這張圖片轉換成base64格式,然后下載。
代碼示意:
var funDownload = function (domImg, filename) { // 創建隱藏的可下載鏈接 var eleLink = document.createElement('a'); eleLink.download = filename; eleLink.style.display = 'none'; // 圖片轉base64地址 var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); var width = domImg.naturalWidth; var height = domImg.naturalHeight; context.drawImage(domImg, 0, 0); // 如果是PNG圖片,則canvas.toDataURL('image/png') eleLink.href = canvas.toDataURL('image/jpeg'); // 觸發點擊 document.body.appendChild(eleLink); eleLink.click(); // 然后移除 document.body.removeChild(eleLink); };
不止是.html
文件,.txt
, .json
等只要內容是文本的文件,都是可以利用這種小技巧實現下載的。
在Chrome瀏覽器,模擬點擊創建的<a>
元素即使不append
到頁面中,也是可以觸發下載的,但是在Firefox瀏覽器中卻不行,因此,上面的funDownload()
方法有一個appendChild
和removeChild
的處理,就是為了兼容Firefox瀏覽器
總結
其實第二和第三種方法是擴展發揮了iframe和form的用法,單獨來看,我們知道iframe可以在父頁面里嵌套子頁面,知道form的action可以發請求或者跳轉頁面,這是很常見的功能,但是不知道它們會被用在下載文件這個需求上,且產生
的效果非常好。
有的類型的文件下載不了,方法二、三、四本質上都是改變location.href,當瀏覽器不能‘理解’這種類型時,就會直接下載,反之,瀏覽器就會直接打開,並不會下載
參考