您好,登錄后才能下訂單哦!
1.寫(xiě)在前面
JS要實(shí)現(xiàn)下載功能,一般都是這么幾個(gè)過(guò)程:生成下載的URL,動(dòng)態(tài)創(chuàng)建一個(gè)A標(biāo)簽,并將其href指向生成的URL,然后觸發(fā)A標(biāo)簽的單擊事件,這樣就會(huì)彈出下載對(duì)話框,從而實(shí)現(xiàn)了一個(gè)下載的功能。
這里所說(shuō)的下載,有時(shí)候也可以理解為保存。出于安全考慮,JS肯定無(wú)法直接調(diào)用FileAPI寫(xiě)文件到磁盤(pán),但是卻可以通過(guò)下載來(lái)變相實(shí)現(xiàn)保存功能。
2.幾個(gè)備用知識(shí)點(diǎn)
2.1. JS觸發(fā)單擊事件
既然是用A標(biāo)簽?zāi)M,那么肯定要知道JS如何主動(dòng)觸發(fā)單擊事件。
最簡(jiǎn)單的觸發(fā)單擊事件肯定是elem.click(),平時(shí)在不需要考慮兼容性的場(chǎng)合我都是這么干的,但是畢竟這個(gè)方法有兼容性(具體兼容性如何沒(méi)做過(guò)測(cè)試),所以還是要掌握一個(gè)通用的方法。
以下代碼是網(wǎng)上比較容易找到的一段代碼,我在前面加了一段MouseEvent的判斷:
/** * 觸發(fā)單擊事件 * @param elem 需要觸發(fā)事件的DOM對(duì)象 */ function fireClickEvent(elem) { var event; if(window.MouseEvent) event = new MouseEvent('click'); else { event = document.createEvent('MouseEvents'); event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); } elem.dispatchEvent(event); }
2.2. HTML5的download屬性
這個(gè)屬性很重要,它可以指定下載文件名,并且可以告訴瀏覽器目標(biāo)鏈接是一個(gè)下載鏈接,不是一個(gè)普通鏈接,我們看下面代碼就能看出區(qū)別了:
<a href="data:text/txt;charset=utf-8,測(cè)試下載純文本" rel="external nofollow" rel="external nofollow" rel="external nofollow" download="測(cè)試.txt" >下載1</a> <a href="data:text/txt;charset=utf-8,測(cè)試下載純文本" rel="external nofollow" rel="external nofollow" rel="external nofollow" >下載2</a>
可以發(fā)現(xiàn),下載1按鈕能夠?qū)崿F(xiàn)下載,點(diǎn)擊下載2鏈接時(shí)直接在瀏覽器打開(kāi)文件內(nèi)容了。
補(bǔ)充說(shuō)明:
file:///模式下貌似不生效;
鏈接指向一些第三方鏈接時(shí)也不會(huì)生效,具體有待研究;
2.3. JS彈出下載對(duì)話框
假如給我們的不是一個(gè)下載地址而是一個(gè)blob對(duì)象,我們可以通過(guò)URL.createObjectURL來(lái)給blob對(duì)象生成臨時(shí)URL,并且可以利用HTML5的download屬性來(lái)指定下載的文件名,好家伙,有了這2個(gè)東西我們就可以實(shí)現(xiàn)一個(gè)“萬(wàn)能”的彈出下載對(duì)話框方法了。
綜上所述,我又在fireClickEvent的基礎(chǔ)上繼續(xù)簡(jiǎn)單封裝了一個(gè)openDownloadDialog方法,使用如下:
openDownloadDialog(url, saveName) openDownloadDialog(blob, saveName)
代碼如下:
/** * 通用的打開(kāi)下載對(duì)話框方法,沒(méi)有測(cè)試過(guò)具體兼容性 * @param url 下載地址,也可以是一個(gè)blob對(duì)象,必選 * @param saveName 保存文件名,可選 */ function openDownloadDialog(url, saveName) { if(typeof url == 'object' && url instanceof Blob) { url = URL.createObjectURL(url); // 創(chuàng)建blob地址 } var aLink = document.createElement('a'); aLink.href = url; aLink.download = saveName || ''; // HTML5新增的屬性,指定保存文件名,可以不要后綴,注意,file:///模式下不會(huì)生效 var event; if(window.MouseEvent) event = new MouseEvent('click'); else { event = document.createEvent('MouseEvents'); event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); } aLink.dispatchEvent(event); }
3.JS實(shí)現(xiàn)常見(jiàn)文件類型的下載
3.1. JS生成CSV文件并下載
csv是一種逗號(hào)分隔的表格文件格式,可以很好的被Excel支持,由于其文件格式簡(jiǎn)單,所以經(jīng)常用在簡(jiǎn)單的表格上面。最重要的是它是一種純文本格式,可以很輕松地用JS來(lái)生成而不借助第三方庫(kù)。
3.1.1. CSV格式示例
如下:
姓名,期中成績(jī),期末成績(jī) 張三,58,95 李四,98,74 王二,47,38 劉能,15,100 黃五,87,68
excel打開(kāi)效果如下:
3.1.2. 初次嘗試
首先想到的是使用data:text/txt;來(lái)實(shí)現(xiàn),先看一下下載純文本:
<a download="測(cè)試.txt" href="data:text/txt;charset=utf-8,測(cè)試下載純文本" rel="external nofollow" rel="external nofollow" rel="external nofollow" >下載</a>
以上代碼沒(méi)毛病,然后再換成csv。換csv的最大問(wèn)題就是如何處理?yè)Q行,很簡(jiǎn)單,用encodeURIComponent編碼一下就可以了:
<button onclick="test()">下載CSV</button> <script> function test() { var csv = '姓名,期中成績(jī),期末成績(jī)\n張三,58,95\n李四,98,74'; var a = document.createElement('a'); a.href = 'data:text/txt;charset=utf-8,'+encodeURIComponent(csv); a.download = '測(cè)試.csv'; a.click(); // 這里偷個(gè)懶,直接用click模擬 } </script>
3.1.3. 解決CSV亂碼問(wèn)題
雖然我們用的是UTF-8編碼,下載后你會(huì)發(fā)現(xiàn),用文本編輯器打開(kāi)沒(méi)問(wèn)題,但是用Excel打開(kāi)亂碼:
別急,原因就是少了一個(gè)\ufeffBOM頭,改成這樣就沒(méi)問(wèn)題了:
<button onclick="test()">下載CSV</button> <script> function test() { var csv = '姓名,期中成績(jī),期末成績(jī)\n張三,58,95\n李四,98,74'; var a = document.createElement('a'); a.href = 'data:text/txt;charset=utf-8,\ufeff'+encodeURIComponent(csv); a.download = '測(cè)試.csv'; a.click(); // 這里偷個(gè)懶,直接用click模擬 } </script>
3.1.4. 繼續(xù)解決下載文件名的問(wèn)題
大部分瀏覽器可能都沒(méi)啥問(wèn)題,但是一些比較老的Chrome可能下載的時(shí)候指定的download就是不生效,此時(shí)可以用blob來(lái)解決:
var csv = '姓名,期中成績(jī),期末成績(jī)\n張三,58,95\n李四,98,74'; var blob = new Blob(['\ufeff' + data], {type: 'text/csv,charset=UTF-8'}); openDownloadDialog(blob, '測(cè)試.csv');
建議一般情況下都用這種方法,穩(wěn)妥一點(diǎn)。
3.1.5. 最后總結(jié)
不考慮兼容性的保存CSV方法:
/** * 保存CSV文件 * @params csv csv文件內(nèi)容 * @params saveName 保存的文件名 */ function saveCSV(csv, saveName) { var a = document.createElement('a'); a.href = 'data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(csv); a.download = saveName; a.click(); }
考慮兼容性的保存CSV方法:
/** * 保存CSV文件 * @params csv csv文件內(nèi)容 * @params saveName 保存的文件名 */ function saveCSV(csv, saveName) { var blob = new Blob(['\ufeff' + csv], {type: 'text/csv,charset=UTF-8'}); openDownloadDialog(blob, saveName); }
3.2. JS實(shí)現(xiàn)純文本的下載保存
掌握了csv,再去下載純文本基本上就沒(méi)啥問(wèn)題了,就是換一下文件類型而已:
var csv = '你好,我是小茗同學(xué)!\n測(cè)試換行!'; var blob = new Blob([data], {type: 'text/txt,charset=UTF-8'}); openDownloadDialog(blob, '測(cè)試.csv');
3.3. JS實(shí)現(xiàn)圖片的下載保存
網(wǎng)頁(yè)上一般要保存圖片都是從canvas里面拿到的圖片數(shù)據(jù),通過(guò)toDataURL轉(zhuǎn)換為base64數(shù)據(jù):
/** * 將某個(gè)canvas保存為圖片 * @param canvasObj canvas對(duì)象 * @param saveName 保存的名稱 * @param type 保存的圖片格式,如 image/png * @param quality 圖片質(zhì)量,可選0-1 */ function saveImage(canvasObj, saveName, type, quality) { if(!canvasObj) return; type = type || 'image/png'; quality = quality || 0.92; var url = canvasObj.toDataURL(type, quality).replace(/image\/.*?;/, 'image/octet-stream;'); openDownloadDialog(url, saveName); }
擴(kuò)展
關(guān)于文件保存,不嫌麻煩的話,GitHub上面有個(gè)比較出名的庫(kù):https://github.com/eligrey/FileSaver.js/
demo:https://eligrey.com/demos/FileSaver.js/
以上所述是小編給大家介紹的JS實(shí)現(xiàn)彈出下載對(duì)話框及常見(jiàn)文件類型的下載,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)億速云網(wǎng)站的支持!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。