公共Hooks封裝文件下載useDownloadFile實(shí)例詳解
引言
對(duì)于經(jīng)常需要開發(fā)企業(yè)管理后臺(tái)的前端開發(fā)來說,必不可少的需要使用表格對(duì)于數(shù)據(jù)進(jìn)行操作,在對(duì)于現(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
對(duì)于企業(yè)管理后臺(tái)中常見的各類資源文件(圖片、文檔、音視頻等),下載保存本地則是再正常不過的需求了,為保證統(tǒng)一性和避免每個(gè)單頁面文件內(nèi)重復(fù)書寫冗余代碼,封裝此方法
封裝前提:各方法對(duì)比
| 方法 | 操作原理 | 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|---|---|
| form 表單 | 動(dòng)態(tài)生成一個(gè)表單,利用表單提交的功能來實(shí)現(xiàn)文件的下載 | 兼容性好,不會(huì)出現(xiàn)URL長(zhǎng)度限制問題 | 無法知道下載的進(jìn)度,用戶體驗(yàn)交互差 無法直接下載瀏覽器可直接預(yù)覽的文件類型 |
| window.open / location.href | 打開新標(biāo)簽頁訪問下載資源 | 簡(jiǎn)單粗暴 | 會(huì)出現(xiàn)URL長(zhǎng)度限制問題 無法知道下載的進(jìn)度,用戶體驗(yàn)交互差 無法直接下載瀏覽器可直接預(yù)覽的文件類型 需要注意url編碼問題 不能添加header,也就不能進(jìn)行鑒權(quán) |
| <a /> download 屬性 | 利用a標(biāo)簽原生訪問屬性,附加新增的download屬性,使用瀏覽器進(jìn)行下載 | 簡(jiǎn)單粗暴且可下載正常預(yù)覽文件 | 不能下載跨域地址文件 IE/Edge內(nèi)兼容問題 無法鑒權(quán) |
| Blob 對(duì)象 | 發(fā)請(qǐng)求獲取二進(jìn)制數(shù)據(jù),轉(zhuǎn)化為Blob對(duì)象,利用URL.createObjectUrl生成url地址,賦值在a標(biāo)簽的href屬性上,結(jié)合download進(jìn)行下載 | 能解決不能直接下載瀏覽器可瀏覽的文件 可以鑒權(quán) | IE10以下不可用 Safari使用情況可能有問題 |
綜上并結(jié)合實(shí)際項(xiàng)目,最后使用Blob對(duì)象進(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)識(shí),
- 下載失敗后,提示用戶,重新下載
createVNode('div', {}, ['文件下載過程中請(qǐng)勿關(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ā)生異常,請(qǐng)重試',
});
}
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', {}, ['文件下載過程中請(qǐng)勿關(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ā)生異常,請(qǐng)重試',
});
}
};
return {
downloadFile,
};
}以上就是公共Hooks封裝文件下載useDownloadFile實(shí)例詳解的詳細(xì)內(nèi)容,更多關(guān)于公共Hooks封裝文件下載的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue.js指令v-model實(shí)現(xiàn)方法
這篇文章主要為大家詳細(xì)介紹了vue.js指令v-model實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12
vue項(xiàng)目開發(fā)環(huán)境工具node搭建過程
最近在開始接觸做vue框架的前端項(xiàng)目,以前用的前端比如html,js,css等都是比較原生的,寫好后直接瀏覽器打開就行,今天就先記錄一下vue的開發(fā)運(yùn)行搭建過程,感興趣的朋友一起看看吧2023-09-09
Vue.js列表渲染綁定jQuery插件的正確姿勢(shì)
這篇文章主要為大家詳細(xì)介紹了Vue.js列表渲染綁定jQuery插件的正確姿勢(shì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
vue項(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-09
vue項(xiàng)目根據(jù)不同環(huán)境進(jìn)行設(shè)置打包命令的方法
這篇文章主要介紹了vue項(xiàng)目根據(jù)不同環(huán)境進(jìn)行設(shè)置打包命令,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-11-11
vue2之響應(yīng)式雙向綁定,在對(duì)象或數(shù)組新增屬性頁面無響應(yīng)的情況
這篇文章主要介紹了vue2之響應(yīng)式雙向綁定,在對(duì)象或數(shù)組新增屬性頁面無響應(yīng)的情況及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04

