公共Hooks封裝文件下載useDownloadFile實(shí)例詳解
引言
對于經(jīng)常需要開發(fā)企業(yè)管理后臺的前端開發(fā)來說,必不可少的需要使用表格對于數(shù)據(jù)進(jìn)行操作,在對于現(xiàn)有項(xiàng)目進(jìn)行代碼優(yōu)化時(shí),封裝一些公共的Hooks.
本篇文章為useDownloadFile.js
基于個(gè)人項(xiàng)目環(huán)境進(jìn)行封裝的Hooks,僅以本文介紹封裝Hooks思想心得,故相關(guān)代碼可能不適用他人
項(xiàng)目環(huán)境
Vue3.x + Ant Design Vue3.x + Vite3.x
對于企業(yè)管理后臺中常見的各類資源文件(圖片、文檔、音視頻等),下載保存本地則是再正常不過的需求了,為保證統(tǒng)一性和避免每個(gè)單頁面文件內(nèi)重復(fù)書寫冗余代碼,封裝此方法
封裝前提:各方法對比
方法 | 操作原理 | 優(yōu)點(diǎn) | 缺點(diǎn) |
---|---|---|---|
form 表單 | 動態(tài)生成一個(gè)表單,利用表單提交的功能來實(shí)現(xiàn)文件的下載 | 兼容性好,不會出現(xiàn)URL長度限制問題 | 無法知道下載的進(jìn)度,用戶體驗(yàn)交互差 無法直接下載瀏覽器可直接預(yù)覽的文件類型 |
window.open / location.href | 打開新標(biāo)簽頁訪問下載資源 | 簡單粗暴 | 會出現(xiàn)URL長度限制問題 無法知道下載的進(jìn)度,用戶體驗(yàn)交互差 無法直接下載瀏覽器可直接預(yù)覽的文件類型 需要注意url編碼問題 不能添加header,也就不能進(jìn)行鑒權(quán) |
<a /> download 屬性 | 利用a標(biāo)簽原生訪問屬性,附加新增的download屬性,使用瀏覽器進(jìn)行下載 | 簡單粗暴且可下載正常預(yù)覽文件 | 不能下載跨域地址文件 IE/Edge內(nèi)兼容問題 無法鑒權(quán) |
Blob 對象 | 發(fā)請求獲取二進(jìn)制數(shù)據(jù),轉(zhuǎn)化為Blob對象,利用URL.createObjectUrl生成url地址,賦值在a標(biāo)簽的href屬性上,結(jié)合download進(jìn)行下載 | 能解決不能直接下載瀏覽器可瀏覽的文件 可以鑒權(quán) | IE10以下不可用 Safari使用情況可能有問題 |
綜上并結(jié)合實(shí)際項(xiàng)目,最后使用Blob對象進(jìn)行封裝下載文件方法
封裝分解:下載核心代碼
xhr.onloadend = function (e) { if (e.target.status === 200 || e.target.status === 304) { const aElement = document.createElement('a'); const blob = e.target.response; const url = window.URL.createObjectURL(blob); aElement.style.display = 'none'; aElement.href = url; aElement.download = `${options.fileName}.${fileType}`; document.body.appendChild(aElement); aElement.click(); if (window.URL) { window.URL.revokeObjectURL(blob); } else { window.webkitURL.revokeObjectURL(blob); } document.body.removeChild(aElement); } }; xhr.send();
封裝分解:用戶體驗(yàn)設(shè)計(jì)
- 下載過程中,配合項(xiàng)目使用的Ant Design Vue框架,可以加強(qiáng)用戶感知文件下載進(jìn)度,
- 為防止用戶暴力點(diǎn)擊,重復(fù)觸發(fā)下載的問題,使用Loading Flag標(biāo)識,
- 下載失敗后,提示用戶,重新下載
createVNode('div', {}, ['文件下載過程中請勿關(guān)閉當(dāng)前頁面']), createVNode('div', { className: 'mt-2' }, [`當(dāng)前下載進(jìn)度 ${progress.value}%`]), catch (e) { console.error(e); downloading = false; infoModal && infoModal.destroy(); Modal.error({ title: '提示', content: '下載發(fā)生異常,請重試', }); }
useDownloadFile.js完整代碼
import { createVNode, ref, onBeforeUnmount } from 'vue'; import { Modal } from 'ant-design-vue'; export function useDownloadFile() { let xhr = null; let downloading = false; // 限制同一文件同時(shí)觸發(fā)多次下載 let infoModal; onBeforeUnmount(() => { xhr && xhr.abort(); }); const downloadFile = options => { try { if (downloading || !options.url || !options.fileName) return; downloading = true; options.url = options.url.replace('http://', 'https://'); const progress = ref(0); const fileType = options.url.split('.').pop(); xhr = new XMLHttpRequest(); xhr.responseType = 'blob'; xhr.open('get', options.url, true); infoModal = Modal.info({ title: '文件下載', okText: '取消下載', content: () => { return createVNode('div', {}, [ createVNode('div', {}, ['文件下載過程中請勿關(guān)閉當(dāng)前頁面']), createVNode('div', { className: 'mt-2' }, [`當(dāng)前下載進(jìn)度 ${progress.value}%`]), ]); }, onOk() { xhr.abort(); return Promise.resolve(); }, }); xhr.onprogress = function (e) { progress.value = Math.floor((e.loaded / e.total) * 100); if (progress.value === 100) { downloading = false; infoModal.destroy(); } }; xhr.onloadend = function (e) { if (e.target.status === 200 || e.target.status === 304) { const aElement = document.createElement('a'); const blob = e.target.response; const url = window.URL.createObjectURL(blob); aElement.style.display = 'none'; aElement.href = url; aElement.download = `${options.fileName}.${fileType}`; document.body.appendChild(aElement); aElement.click(); if (window.URL) { window.URL.revokeObjectURL(blob); } else { window.webkitURL.revokeObjectURL(blob); } document.body.removeChild(aElement); } }; xhr.send(); } catch (e) { console.error(e); downloading = false; infoModal && infoModal.destroy(); Modal.error({ title: '提示', content: '下載發(fā)生異常,請重試', }); } }; return { downloadFile, }; }
以上就是公共Hooks封裝文件下載useDownloadFile實(shí)例詳解的詳細(xì)內(nèi)容,更多關(guān)于公共Hooks封裝文件下載的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue.js指令v-model實(shí)現(xiàn)方法
這篇文章主要為大家詳細(xì)介紹了vue.js指令v-model實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12vue項(xiàng)目開發(fā)環(huán)境工具node搭建過程
最近在開始接觸做vue框架的前端項(xiàng)目,以前用的前端比如html,js,css等都是比較原生的,寫好后直接瀏覽器打開就行,今天就先記錄一下vue的開發(fā)運(yùn)行搭建過程,感興趣的朋友一起看看吧2023-09-09vue項(xiàng)目在IE瀏覽器下運(yùn)行空白問題及解決
IE11瀏覽器無法解析ES6語法導(dǎo)致Vue項(xiàng)目在IE11下顯示空白,解決方法包括安裝babel-polyfill,并在項(xiàng)目的main.js文件中引入babel-polyfill,此外,js-base64版本3及以上不兼容IE11,解決辦法是使用版本3以下的js-base64,這些措施可以幫助兼容IE11,確保項(xiàng)目正常運(yùn)行2024-09-09vue項(xiàng)目根據(jù)不同環(huán)境進(jìn)行設(shè)置打包命令的方法
這篇文章主要介紹了vue項(xiàng)目根據(jù)不同環(huán)境進(jìn)行設(shè)置打包命令,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-11-11vue2之響應(yīng)式雙向綁定,在對象或數(shù)組新增屬性頁面無響應(yīng)的情況
這篇文章主要介紹了vue2之響應(yīng)式雙向綁定,在對象或數(shù)組新增屬性頁面無響應(yīng)的情況及解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04