在實(shí)際開發(fā)過程中,有時(shí)需要將圖表或者地圖等基于Canvas技術(shù)渲染的數(shù)據(jù)下載到本地保存到情況,下面介紹兩種方法來完成這種功能。
一、a 標(biāo)簽法
a 標(biāo)簽方法主要分為以下步驟:
- 將 canvas 元素的數(shù)據(jù)通過原生 api 轉(zhuǎn)換成 base64 編碼的圖片格式
- 利用 a 標(biāo)簽設(shè)置 download 屬性可以將 href 鏈接元素下載,我們將 a 標(biāo)簽的 href 屬性值設(shè)置為上一步獲得的 base64 格式字符串
- 構(gòu)造一個(gè)單擊事件并通過 api 觸發(fā) a 標(biāo)簽的 click 事件完成下載
注意點(diǎn):由于瀏覽器安全限制,事件觸發(fā)的代碼不能被異步代碼包裹
以下為代碼示例:
index.html
<!-- 待下載對(duì) canvas 元素 -->
<!-- 移動(dòng)端可能會(huì)由于 viewport 的原因?qū)е孪螺d的圖片不清晰,我們可以在 canvas 標(biāo)簽上直接設(shè)置 width 和 height 屬性,不采用 style 中的 width 和 height, 相當(dāng)于設(shè)置內(nèi)部分辨率 -->
<canvas id="chart" width="1920" height="1080"></canvas>
<!-- 觸發(fā)下載操作的按鈕 -->
<button onclick="download('#chart')">下載</button>
download.js
function download(selector) {
// 通過 API 獲取目標(biāo) canvas 元素
const canvas = document.querySelector(selector);
// 創(chuàng)建一個(gè) a 標(biāo)簽,并設(shè)置 href 和 download 屬性
const el = document.createElement('a');
// 設(shè)置 href 為圖片經(jīng)過 base64 編碼后的字符串,默認(rèn)為 png 格式
el.href = canvas.toDataURL();
el.download = '文件名稱';
// 創(chuàng)建一個(gè)點(diǎn)擊事件并對(duì) a 標(biāo)簽進(jìn)行觸發(fā)
const event = new MouseEvent('click');
el.dispatchEvent(event);
}
下面我們總結(jié)下 a 標(biāo)簽法的優(yōu)缺點(diǎn):
- 優(yōu)點(diǎn):只使用瀏覽器提供的原生 API 就能實(shí)現(xiàn)我們的需求。
- 缺點(diǎn):無法被異步代碼包裹,也就是包含 Ajax 請(qǐng)求的情況下代碼不生效。
- 缺點(diǎn):對(duì)于分辨率過高的 canvas, 我們生成的 dataURL 過長,超過瀏覽器限制,可能會(huì)導(dǎo)致無法順利下載,如出現(xiàn)此現(xiàn)象請(qǐng)參考下面介紹的方法。
二、saveAs 法
使用這種方法我們需要用到一個(gè)三方庫 FileSaver.js,該庫實(shí)現(xiàn)了 HTML5 規(guī)范中的 saveAs 方法。
該方法的主要步驟如下:
- 通過 canvas 的 toBlob API 將數(shù)據(jù)轉(zhuǎn)換為二進(jìn)制格式。
- 通過 FileSaver.js 提供的 saveAs 方法對(duì)該二進(jìn)制進(jìn)行下載。
下面是我們的實(shí)現(xiàn):
index.html
<!-- 通過 CDN 引入 FileSaver.js -->
<!-- 我們也可以通過 npm 引入 https://www.npmjs.com/package/file-saver
-->
<script src="https://cdn.bootcss.com/FileSaver.js/1.3.8/FileSaver.min.js"></script>
<!-- 待下載對(duì) canvas 元素 -->
<canvas id="chart" width="1920" height="1080"></canvas>
<!-- 觸發(fā)下載操作的按鈕 -->
<button onclick="download('#chart')">下載</button>
download.js
function download(selector) {
// 通過 API 獲取目標(biāo) canvas 元素
const canvas = document.querySelector(selector);
// 如果 toBlob 方法出現(xiàn)兼容性問題建議引入 https://github.com/eligrey/canvas-toBlob.js
canvas.toBlob(function(blob) {
saveAs(blob, '文件名稱')
});
}
下面我們總結(jié)下 saveAs 法的優(yōu)缺點(diǎn):
- 優(yōu)點(diǎn):基本不限制下載圖片的大?。ú怀^本機(jī)內(nèi)存)
- 缺點(diǎn):需要引入第三方庫
三、涉及的資料
MDN a 標(biāo)簽的說明(包括 download 屬性以及其限制):https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/a
MDN 關(guān)于 toDataURL 說明: https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/toDataURL
MDN 關(guān)于toBlob 說明:https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/toBlob
FileSaver.js Github 主頁:https://github.com/eligrey/FileSaver.js
FilerServer.js NPM 倉庫主頁:https://www.npmjs.com/package/file-saver
canvas-toBlob Github 主頁:https://github.com/eligrey/canvas-toBlob.js
canvas-toBlob NPM 倉庫主頁:https://www.npmjs.com/package/canvas-toBlob
如果有不清楚的地方可以在評(píng)論中提出,我會(huì)及時(shí)作出解答,感謝閱讀!