前言
最近在寫uniapp,第一次寫。。。項(xiàng)目從pc端寫個對應(yīng)的app端。遇到下載功能,想到這功能比較常見,而且社區(qū)很多人遇到這個問題,就多寫點(diǎn),寫通用點(diǎn),后面再遇到也可以用,分享給大家,記得點(diǎn)贊哦!
自行選擇合適方法即可,支持:
1.uniapp h5 端下載。
2.unapp 開發(fā)的頁面嵌入到uniapp webview 中,或者 h5 plus 中
3.uniapp 非h5 端下載 (支持app,其他端自行測試)
4. axios + responseType: "blob" 的下載
5. uni.request + responseType: 'arraybuffer' + window.URL.createObjectURL(返回值) + a標(biāo)簽download方式 下載
代碼如下:
/**
* 文件下載相關(guān)支持axios、uniapp各端
* author: yangfeng
* date: 2023/08/10
* /
/**
* pc端axios方式下載
* 方式一:使用 uni.request + responseType: 'arraybuffer' + window.URL.createObjectURL(返回值) + a標(biāo)簽download方式
* 方式二:使用 axios + responseType: "blob"
* @param {*} arrayBufferOrBlob arraybuffer 或者 blob。若是axios則設(shè)置為 responseType: 'blob',若使用 uni.request 則 responseType: 'arraybuffer'
* @param {*} fileName 需要保存的文件名稱
*/
export function pc_axios_download(arrayBufferOrBlob, fileName) {
const blob = new Blob([arrayBufferOrBlob], {
type: "application/vnd.ms-execl",
});
if (typeof window.navigator.msSaveBlob !== "undefined") {
// 兼容IE,window.navigator.msSaveBlob:以本地方式保存文件
window.navigator.msSaveBlob(blob, decodeURI(fileName));
} else {
// 創(chuàng)建新的URL并指向File對象或者Blob對象的地址
const blobURL = window.URL.createObjectURL(blob);
// 創(chuàng)建a標(biāo)簽,用于跳轉(zhuǎn)至下載鏈接
const tempLink = document.createElement("a");
tempLink.style.display = "none";
tempLink.href = blobURL;
tempLink.setAttribute("download", decodeURI(fileName));
// 兼容:某些瀏覽器不支持HTML5的download屬性
if (typeof tempLink.download === "undefined") {
tempLink.setAttribute("target", "_blank");
}
// 掛載a標(biāo)簽
document.body.appendChild(tempLink);
tempLink.click();
document.body.removeChild(tempLink);
// 釋放blob URL地址
window.URL.revokeObjectURL(blobURL);
}
}
/**
* h5方式下載臨時路徑的文件 - 創(chuàng)建a標(biāo)簽,download的方式
* @param {*} blobURL 附件的臨時路徑
* @param {*} fileName 下載后的該文件名稱
*/
export function h5_download(blobURL, fileName) {
// 創(chuàng)建a標(biāo)簽,用于跳轉(zhuǎn)至下載鏈接
const tempLink = document.createElement("a");
tempLink.style.display = "none";
tempLink.href = blobURL;
tempLink.setAttribute("download", decodeURI(fileName));
// 兼容:某些瀏覽器不支持HTML5的download屬性
if (typeof tempLink.download === "undefined") {
tempLink.setAttribute("target", "_blank");
}
// 掛載a標(biāo)簽
document.body.appendChild(tempLink);
tempLink.click();
document.body.removeChild(tempLink);
// 釋放blob URL地址
window.URL.revokeObjectURL(blobURL);
}
function checkDownload() {
plus.io.requestFileSystem(plus.io.PUBLIC_DOWNLOADS, function (fs) {
var directoryReader = fs.root.createReader();
directoryReader.readEntries(
function (entries) {
var i;
for (i = 0; i < entries.length; i++) {
console.log(entries[i].name);
entries[i].name = i;
}
},
function (e) {
console.log("Read entries failed: " + e.message);
}
);
});
}
// h5Plus 下載 - plus.downloader.createDownload api
export function h5Plus_download(url, options = {}) {
return new Promise((resolve, reject) => {
let dtask = plus.downloader.createDownload(
url,
options,
function (d, status) {
if (status == 200) {
//下載成功,d.filename是文件在保存在本地的相對路徑,使用下面的API可轉(zhuǎn)為平臺絕對路徑
let fileSaveUrl = plus.io.convertLocalFileSystemURL(d.filename);
console.log(fileSaveUrl, "平臺絕對路徑");
uni.showModal({
title: "下載成功,是否打開文件?",
content: "文件目錄存儲目錄為:" + fileSaveUrl,
success: function (res) {
if (res.confirm) {
// console.log('用戶點(diǎn)擊確定');
//選擇軟件打開文件
plus.runtime.openFile(d.filename);
} else if (res.cancel) {
// console.log('用戶點(diǎn)擊取消');
}
},
});
resolve(d);
// checkDownload()
// console.log("Download success: " + JSON.stringify(d));
// 保存圖片、視頻到相冊中
// plus.gallery.save(d.filename, function () {
// resolve(d);
// console.log( "保存圖片到相冊成功" );
// // 打開文件
// plus.runtime.openFile(d.filename, (err) => {
// console.log(err);
// });
// },function(){
// reject();
// console.log( "保存圖片到相冊失敗" );
// });
// let arr = fileSaveUrl.split('/')
// let dirPath = arr.slice(0, arr.length-1).join('/') // 當(dāng)前文件所在目錄
// console.log(getApp().globalData, dirPath, 666)
// // 通過URL參數(shù)獲取目錄對象或文件對象
// plus.io.resolveLocalFileSystemURL(dirPath, function( entry ) {
// console.log(entry, 44)
// // 打開文件目錄
// entry.getDirectory('',{create:true,exclusive:false},function( dir ){
// console.log("Directory Entry Name: " + dir.name);
// }, function (e) {
// console.error(e, 444)
// })
// }, function ( e ) {
// alert( "Resolve file URL failed: " + e.message );
// } );
} else {
reject();
console.log("Download failed: " + status);
}
}
);
dtask.start();
});
}
// 非h5下載
export function noH5_download(tempFilePath) {
return new Promise((resolve, reject) => {
uni.saveFile({
tempFilePath: tempFilePath,
success: function (red) {
let savedFilePath = red.savedFilePath; // 相對路徑
let fileSaveUrl = plus.io.convertLocalFileSystemURL(savedFilePath);
console.log(fileSaveUrl, "平臺絕對路徑");
uni.showModal({
title: "提示",
content: "文件已保存:" + fileSaveUrl,
cancelText: "我知道了",
confirmText: "打開文件",
success: function (resMdel) {
if (resMdel.confirm) {
uni.openDocument({
filePath: savedFilePath,
success: (sus) => {
console.log("成功打開");
},
fail(){
uni.showToast({
icon: 'none',
title: '暫不支持打開此格式文件'
})
}
});
}
},
});
resolve(red);
},
fail(e) {
console.error(e);
reject(e);
},
});
});
}
/**
*下載文件資源到本地,客戶端直接發(fā)起一個 HTTP GET 請求,返回文件的本地臨時路徑。注意:1.h5可能存在跨域問題 2.只支持get方式下載
* @param {*} url 下載的完整路徑
* @param {*} fileName 下載后的該文件名稱
* @param {*} config uni.downloadFile的其他配置,如可以在header 添加token參數(shù)
* @returns Promise<any>
*/
export function uni_DownloadFile(url, fileName, config = {}) {
return new Promise((resolve, reject) => {
uni.downloadFile({
url: url, //僅為示例,并非真實(shí)的資源
// header: {
// "x-token": useUserStore().token,
// },
...config,
success: (res) => {
let tempFilePath = res.tempFilePath;
// console.log(res, 4444);
// h5 方式下載
// #ifdef H5
let isPlus = null;
try {
isPlus = plus;
} catch (e) {}
if (isPlus) {
// 是否支持h5 plus,針對當(dāng)前頁面被uniapp webview 引入 或者被包裹在 h5+ 殼子里,使用 h5plus 方式下載
// 采用a標(biāo)簽download方式下載會失敗,因此需要針對處理
// 雖然會彈出下載框,但是下載之后你發(fā)現(xiàn)打開時失敗,文件路徑錯誤;這是因?yàn)閣ebview中下載文件出現(xiàn)套娃現(xiàn)象
console.log("當(dāng)前是h5 嵌入到 h5+ 環(huán)境");
h5Plus_download(url, { filename: "_downloads/" + fileName })
.then((result) => {
resolve(result);
})
.catch(() => {
reject();
});
} else {
console.log("當(dāng)前是h5環(huán)境下載");
// window.location.href= tempFilePath
h5_download(tempFilePath, fileName);
resolve(res);
}
// #endif
// 非 h5 方式下載 - 需要保存文件到本地,如app里面的下載
// #ifndef H5
console.log("當(dāng)前非h5環(huán)境下載");
noH5_download(tempFilePath)
.then((result) => {
resolve(result);
})
.catch(() => {
reject();
});
// #endif
},
fail(e) {
console.error(e);
reject(e);
},
});
});
}
調(diào)用方式:
1.uni 方式下載,兼容多端,如h5、嵌入到webview的h5、嵌入到h5 plus 環(huán)境的h5、uniapp vueapp等,其他的自行測試
/**
* 根據(jù)下載路徑下載文件
* @param {*} url 下載路徑,絕對路徑,必選
* @param {*} fileName 下載文件名稱,必選
* @returns
*/
export const downloadFileFromUrl = (url, fileName) => {
// uni方式 下載
return uni_DownloadFile(url,fileName,{
header: {
"x-token": useUserStore().token,
},
})
// pc、h5 方式下載
// return service
// .request({
// url: url,
// method: "get",
// // responseType: "blob", // axios 等pc端通用下載
// responseType: 'arraybuffer', // uni.request方式下載 文檔里說這里只有text、arraybuffer,因此不能使用blob
// headers: {
// "x-token": useUserStore().token,
// },
// }, false)
// .then((res) => {
// // console.log(res,res.data, 111)
// if(res.status !== 200) return Promise.reject(res.errMsg || res.message || '下載失敗')
// pc_axios_download(
// res.data,
// fileName ||
// (res.headers || res.header)["content-disposition"].replace(
// /.+filename=(.+)$/,
// "$1"
// ) ||
// url.split("/").pop()
// );
// })
// .catch((err) => {
// console.log(err);
// return Promise.reject(err);
// });
};
2. uni.request 方式在h5端下載
/**
* 根據(jù)下載路徑下載文件
* @param {*} url 下載路徑,絕對路徑,必選
* @param {*} fileName 下載文件名稱,必選
* @returns
*/
export const downloadFileFromUrl = (url, fileName) => {
// uni方式 下載
// return uni_DownloadFile(url,fileName,{
// header: {
// "x-token": useUserStore().token,
// },
// })
// pc、h5 方式下載
return service
.request({
url: url,
method: "get",
// responseType: "blob", // axios 等pc端通用下載
responseType: 'arraybuffer', // uni.request方式下載 文檔里說這里只有text、arraybuffer,因此不能使用blob
header: {
"x-token": useUserStore().token,
},
}, false)
.then((res) => {
// console.log(res,res.data, 111)
if(res.status !== 200) return Promise.reject(res.errMsg || res.message || '下載失敗')
pc_axios_download(
res.data,
fileName ||
(res.headers || res.header)["content-disposition"].replace(
/.+filename=(.+)$/,
"$1"
) ||
url.split("/").pop()
);
})
.catch((err) => {
console.log(err);
return Promise.reject(err);
});
};
3.axios 方式下載,這樣pc端也可以用
/**
* 根據(jù)下載路徑下載文件
* @param {*} url 下載路徑,絕對路徑,必選
* @param {*} fileName 下載文件名稱,必選
* @returns
*/
export const downloadFileFromUrl = (url, fileName) => {
// uni方式 下載
// return uni_DownloadFile(url,fileName,{
// header: {
// "x-token": useUserStore().token,
// },
// })
// pc、h5 方式下載
return service
.request({
url: url,
method: "get",
responseType: "blob", // axios 等pc端通用下載
// responseType: 'arraybuffer', // uni.request方式下載 文檔里說這里只有text、arraybuffer,因此不能使用blob
headers: {
"x-token": useUserStore().token,
},
}, false)
.then((res) => {
// console.log(res,res.data, 111)
if(res.status !== 200) return Promise.reject(res.errMsg || res.message || '下載失敗')
pc_axios_download(
res.data,
fileName ||
(res.headers || res.header)["content-disposition"].replace(
/.+filename=(.+)$/,
"$1"
) ||
url.split("/").pop()
);
})
.catch((err) => {
console.log(err);
return Promise.reject(err);
});
};
注意:我這邊自行將uni.request封裝了下,調(diào)用方式向axios靠齊的,本來我這邊調(diào)用沒這么復(fù)雜,后面兩種其實(shí)差不多。這里還是分開寫的,避免有些同學(xué)搞不清楚。比如uni.request 是header不是headers,responseType只有arraybuffer沒有blob等。
總結(jié):
這邊的項(xiàng)目目前采用webview引入uniapp開發(fā)的頁面的方式,這樣簡單點(diǎn),相當(dāng)于iframe直接引入,很多pc端代碼可以直接復(fù)用【這是個低代碼平臺,能少改點(diǎn)最好不過】【才不是因?yàn)橹苯哟虺蒩pp各種報錯。。。】。后面發(fā)現(xiàn)嵌入到uniapp webview里面是沒法使用a標(biāo)簽download下載這種方式的,雖然會彈出下載框但是會下載失敗,瀏覽器上是正常下載的。因此采用的h5 plus 方式下載。
注意:
1.如果在h5 plus 下遇到下載失敗,看下是否 plusready 完成

app 端可以直接使用h5+ api

2.若遇到這個報錯: Refused to get unsafe header "content-disposition"

后端設(shè)置下resopnse content-disposition 應(yīng)該就行了,不管他也沒啥,不影響下載。
若對你有幫助,請點(diǎn)個贊吧,謝謝支持!
本文地址:http://www.itdecent.cn/p/d827dd9ed17e?v=1691636612446,轉(zhuǎn)載請注明出處,謝謝。