前端js下载文件优化函数,可直接使用 2025年9月25日 143 代码厨子 我们用arco作为前端UI框架,TS写vue,下载文件一直是有点体验不好,特别大文件下载。下决心修改了函数,可以直接拿走不谢。 ### 以下是PC端的函数源代码,能解决大文件下载时候的进度读取问题,注意,使用的是arco框架,其他框架自行修改提示方式。 ```javascript export const download = async (imageUrl: string, fileName: string, timeout = 300000000) => { // 创建初始加载提示 const progressInstance = Message.loading({ id: 'downloadProgress', content: '开始准备下载...', duration: 0, // 不自动关闭 closable: false }) try { const blob = await new Promise<Blob>((resolve, reject) => { const xhr = new XMLHttpRequest() xhr.open('GET', imageUrl, true) xhr.responseType = 'blob' // 超时控制 const timer = setTimeout(() => { xhr.abort() reject(new Error('下载超时,请重试')) }, timeout) // 进度事件 - 通过关闭旧实例创建新实例来更新进度 xhr.onprogress = (e) => { // 先关闭旧的提示 // progressInstance.close() // 创建新的提示显示最新进度 if (e.lengthComputable) { const percent = Math.round((e.loaded / e.total) * 100) Message.loading({ id: 'downloadProgress', content: `正在下载... ${percent}%`, duration: 0, closable: false }) } else { Message.loading({ id: 'downloadProgress', content: '正在下载中...', duration: 0, closable: false }) } } // 成功回调 xhr.onload = () => { clearTimeout(timer) if (xhr.status === 200) { resolve(xhr.response) } else { reject(new Error(`下载失败,状态码: ${xhr.status}`)) } } // 错误回调 xhr.onerror = () => { clearTimeout(timer) reject(new Error('网络错误,下载失败')) } xhr.send() }) // 保存文件 FileSaver.saveAs(new Blob([blob], { type: 'application/octet-stream' }), fileName) // 关闭进度提示,显示成功信息 progressInstance.close() Message.success({ content: '浏览器已自动下载保存', duration: 3000 }) } catch (error) { // 关闭进度提示,显示错误信息 progressInstance.close() const errorMsg = error instanceof Error ? error.message : '下载失败,请重试' Message.error({ content: errorMsg, duration: 3000 }) } } ``` ### 以下是移动端代码,移动端是使用uni-app,提示信息也是使用其内置组件。 ```javascript export default function downloadFileUrl(url, fileName, method, timeout = 60000) { // 显示初始加载提示 let progressTitle = '开始下载...' uni.showLoading({ title: progressTitle, mask: true }) // 超时控制定时器 let timeoutTimer = setTimeout(() => { handleError('下载超时,请重试') }, timeout) // 错误处理统一方法 function handleError(message) { clearTimeout(timeoutTimer) uni.hideLoading() uni.showToast({ title: message, icon: 'none', duration: 3000 }) } // #ifdef H5 const xhr = new XMLHttpRequest() xhr.open("GET", url, true) xhr.responseType = 'blob' // 进度更新 xhr.onprogress = (e) => { if (e.lengthComputable) { const percent = Math.round((e.loaded / e.total) * 100) progressTitle = `正在下载...${percent}%` // 更新加载提示 uni.showLoading({ title: progressTitle, mask: true }) } } xhr.onload = function() { clearTimeout(timeoutTimer) uni.hideLoading() if (this.status === 200) { try { const url = window.URL.createObjectURL(this.response) const a = document.createElement('a') a.href = url a.download = fileName || '下载文件' a.click() window.URL.revokeObjectURL(url) // 释放URL对象 uni.showToast({ title: '已通过浏览器下载', icon: 'none', duration: 3000 }) } catch (e) { handleError('下载失败:' + e.message) } } else { handleError(`下载失败,状态码: ${this.status}`) } } xhr.onerror = function() { handleError('网络错误,下载失败') } xhr.send() // #endif // #ifdef MP-WEIXIN uni.downloadFile({ url: url, timeout: timeout, // 小程序自带超时参数 // 进度更新 onProgressUpdate: (res) => { progressTitle = `正在下载...${res.progress}%` uni.showLoading({ title: progressTitle, mask: true }) }, success: (res) => { clearTimeout(timeoutTimer) uni.hideLoading() if (res.statusCode === 200) { // 根据类型保存 const saveApi = method === 0 ? 'saveImageToPhotosAlbum' : 'saveVideoToPhotosAlbum' uni[saveApi]({ filePath: res.tempFilePath, success: () => { uni.showToast({ title: '已保存到相册', icon: 'success', duration: 3000 }) }, fail: (err) => { // 处理授权失败情况 if (err.errMsg.includes('auth deny')) { handleError('请开启保存到相册的权限') } else { handleError('保存失败:' + err.errMsg) } } }) } else { handleError(`下载失败,状态码: ${res.statusCode}`) } }, fail: (err) => { handleError('下载失败:' + (err.errMsg || '未知错误')) } }) // #endif } ```