前言
在 Vue中实现请求并下载导入模板的功能,通常需要后端提供一个模板文件的下载接口。 下列以Vue3
为例。
1.基本实现方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import { ref } from 'vue' import axios from 'axios' import { ElMessage } from 'element-plus'
const downloadTemplate = async () => { try { const response = await axios.get('/api/template/download', { responseType: 'blob', params: { templateType: 'your-template-type' } }) const url = window.URL.createObjectURL(new Blob([response.data])) const link = document.createElement('a') link.href = url link.setAttribute('download', '导入模板.xlsx') document.body.appendChild(link) link.click() document.body.removeChild(link) window.URL.revokeObjectURL(url) ElMessage.success('模板下载成功') } catch (error) { ElMessage.error('下载失败: ' + (error.message || '请联系管理员')) } }
|
2.封装成可复用组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| <template> <el-button type="primary" :loading="downloading" @click="handleDownload" > 下载导入模板 </el-button> </template>
<script setup> import { ref } from 'vue' import axios from 'axios' import { ElMessage } from 'element-plus'
const downloading = ref(false)
const handleDownload = async () => { downloading.value = true try { const response = await axios.get('/api/template/download', { responseType: 'blob', params: { type: 'import' } }) // 从响应头获取文件名 const contentDisposition = response.headers['content-disposition'] let fileName = '导入模板.xlsx' if (contentDisposition) { const fileNameMatch = contentDisposition.match(/filename=(.+)/) if (fileNameMatch && fileNameMatch[1]) { fileName = decodeURIComponent(fileNameMatch[1]) } } const url = window.URL.createObjectURL(new Blob([response.data])) const link = document.createElement('a') link.href = url link.setAttribute('download', fileName) document.body.appendChild(link) link.click() document.body.removeChild(link) window.URL.revokeObjectURL(url) ElMessage.success('模板下载成功') } catch (error) { ElMessage.error(`下载失败: ${error.message || '请联系管理员'}`) } finally { downloading.value = false } } </script>
|
3. 使用文件流下载(适用于大文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| const downloadLargeTemplate = async () => { try { const response = await fetch('/api/template/download-large') const reader = response.body.getReader() const contentLength = +response.headers.get('Content-Length') let receivedLength = 0 let chunks = [] while(true) { const { done, value } = await reader.read() if (done) break chunks.push(value) receivedLength += value.length console.log(`下载进度: ${Math.round(receivedLength / contentLength * 100)}%`) } const blob = new Blob(chunks) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = '大型导入模板.xlsx' a.click() URL.revokeObjectURL(url) } catch (error) { ElMessage.error('下载失败: ' + error.message) } }
|
4.后端配合示例(Node.js Express)
1 2 3 4 5 6 7 8 9 10 11
| router.get('/api/template/download', (req, res) => { const filePath = path.join(__dirname, '../templates/import-template.xlsx') const fileName = '导入模板.xlsx' res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') res.setHeader('Content-Disposition', `attachment; filename=${encodeURIComponent(fileName)}`) const fileStream = fs.createReadStream(filePath) fileStream.pipe(res) })
|
5.使用第三方库(如 file-saver)
然后使用:
1 2 3 4 5 6 7 8 9 10 11 12 13
| import { saveAs } from 'file-saver'
const downloadWithFileSaver = async () => { try { const response = await axios.get('/api/template/download', { responseType: 'blob' }) saveAs(response.data, '导入模板.xlsx') ElMessage.success('模板下载成功') } catch (error) { ElMessage.error('下载失败: ' + error.message) } }
|
注意事项
- 确保后端设置了正确的
Content-Type
和 Content-Disposition
响应头
- 对于大文件,考虑使用流式下载并显示进度条
- 下载完成后要及时释放创建的 URL 对象,避免内存泄漏
- 根据实际业务需求调整文件名和错误处理逻辑