Vue3实现文件上传、下载及预览全流程详解(含完备接口调用) ...

打印 上一主题 下一主题

主题 1027|帖子 1027|积分 3081




  
一、情况准备

1.1 创建Vue3项目

  1. npm create vue@latest
  2. # 选择TypeScript、Pinia(可选)、ESLint等配置
复制代码
1.2 安装依赖

  1. npm install axios element-plus @element-plus/icons-vue
复制代码
1.3 设置Element Plus

  1. // main.ts
  2. import ElementPlus from 'element-plus'
  3. import 'element-plus/dist/index.css'
  4. const app = createApp(App)
  5. app.use(ElementPlus)
复制代码

二、文件上传实现

2.1 基础上传组件

  1. <template>
  2.   <el-upload
  3.     class="upload-demo"
  4.     :action="uploadUrl"
  5.     :headers="headers"
  6.     :on-success="handleSuccess"
  7.     :before-upload="beforeUpload"
  8.   >
  9.     <el-button type="primary">点击上传</el-button>
  10.     <template #tip>
  11.       <div class="el-upload__tip">支持扩展名:.jpg/.png/.pdf,最大5MB</div>
  12.     </template>
  13.   </el-upload>
  14. </template>
  15. <script setup lang="ts">
  16. import { ref } from 'vue'
  17. import type { UploadProps } from 'element-plus'
  18. const uploadUrl = ref('https://api.example.com/upload')
  19. const headers = ref({
  20.   Authorization: 'Bearer ' + localStorage.getItem('token')
  21. })
  22. // 文件预校验
  23. const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
  24.   const isValidType = ['image/jpeg', 'image/png', 'application/pdf'].includes(rawFile.type)
  25.   const isLt5M = rawFile.size / 1024 / 1024 < 5
  26.   
  27.   if (!isValidType) {
  28.     ElMessage.error('文件格式不支持!')
  29.     return false
  30.   }
  31.   if (!isLt5M) {
  32.     ElMessage.error('文件大小不能超过5MB!')
  33.     return false
  34.   }
  35.   return true
  36. }
  37. // 上传成功回调
  38. const handleSuccess: UploadProps['onSuccess'] = (response) => {
  39.   ElMessage.success('上传成功')
  40.   console.log('服务器返回:', response)
  41.   // 通常返回文件访问地址
  42. }
  43. </script>
复制代码
2.2 自定义上传逻辑(Axios实现)

  1. const customUpload = async (file: File) => {
  2.   const formData = new FormData()
  3.   formData.append('file', file)
  4.   formData.append('userId', '123')
  5.   try {
  6.     const { data } = await axios.post('/api/upload', formData, {
  7.       headers: {
  8.         'Content-Type': 'multipart/form-data',
  9.         Authorization: `Bearer ${localStorage.getItem('token')}`
  10.       }
  11.     })
  12.     return data
  13.   } catch (error) {
  14.     ElMessage.error('上传失败')
  15.     throw error
  16.   }
  17. }
复制代码

三、文件下载实现

3.1 直接下载(已知文件URL)

  1. <template>
  2.   <el-button @click="handleDownload">下载文件</el-button>
  3. </template>
  4. <script setup lang="ts">
  5. const handleDownload = () => {
  6.   const link = document.createElement('a')
  7.   link.href = 'https://api.example.com/files/sample.pdf'
  8.   link.download = 'filename.pdf' // 设置下载文件名
  9.   document.body.appendChild(link)
  10.   link.click()
  11.   document.body.removeChild(link)
  12. }
  13. </script>
复制代码
3.2 后端接口下载(二进制流)

  1. const downloadFile = async (fileId: string) => {
  2.   try {
  3.     const response = await axios.get(`/api/download/${fileId}`, {
  4.       responseType: 'blob'
  5.     })
  6.     // 创建Blob对象
  7.     const blob = new Blob([response.data])
  8.     const url = window.URL.createObjectURL(blob)
  9.    
  10.     // 提取文件名
  11.     const contentDisposition = response.headers['content-disposition']
  12.     const fileName = contentDisposition
  13.       ?.split('filename=')[1]
  14.       ?.replace(/"/g, '')
  15.       || 'download-file'
  16.     // 创建下载链接
  17.     const link = document.createElement('a')
  18.     link.href = url
  19.     link.download = fileName
  20.     document.body.appendChild(link)
  21.     link.click()
  22.     window.URL.revokeObjectURL(url)
  23.     document.body.removeChild(link)
  24.   } catch (error) {
  25.     ElMessage.error('下载失败')
  26.   }
  27. }
复制代码

四、文件预览实现

4.1 图片预览

  1. <template>
  2.   <el-image
  3.     :src="imageUrl"
  4.     :preview-src-list="[imageUrl]"
  5.     fit="cover"
  6.   />
  7. </template>
复制代码
4.2 PDF预览(利用pdf.js)

  1. npm install pdfjs-dist @types/pdfjs-dist
复制代码
  1. <template>
  2.   <div ref="pdfContainer" class="pdf-viewer"></div>
  3. </template>
  4. <script setup lang="ts">
  5. import { ref, onMounted } from 'vue'
  6. import * as pdfjsLib from 'pdfjs-dist'
  7. const props = defineProps<{
  8.   pdfUrl: string
  9. }>()
  10. const pdfContainer = ref<HTMLElement>()
  11. onMounted(async () => {
  12.   const loadingTask = pdfjsLib.getDocument(props.pdfUrl)
  13.   const pdf = await loadingTask.promise
  14.   
  15.   for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
  16.     const page = await pdf.getPage(pageNum)
  17.     const viewport = page.getViewport({ scale: 1.5 })
  18.    
  19.     const canvas = document.createElement('canvas')
  20.     const context = canvas.getContext('2d')!
  21.     canvas.height = viewport.height
  22.     canvas.width = viewport.width
  23.    
  24.     await page.render({
  25.       canvasContext: context,
  26.       viewport: viewport
  27.     }).promise
  28.    
  29.     pdfContainer.value?.appendChild(canvas)
  30.   }
  31. })
  32. </script>
复制代码
4.3 Excel预览(利用xlsx)

  1. npm install xlsx
复制代码
  1. <template>
  2.   <el-table :data="excelData">
  3.     <el-table-column
  4.       v-for="(col, index) in columns"
  5.       :key="index"
  6.       :prop="col"
  7.       :label="col"
  8.     />
  9.   </el-table>
  10. </template>
  11. <script setup lang="ts">
  12. import { read, utils } from 'xlsx'
  13. import { ref } from 'vue'
  14. const excelData = ref([])
  15. const columns = ref([])
  16. const previewExcel = async (file: File) => {
  17.   const data = await file.arrayBuffer()
  18.   const workbook = read(data)
  19.   const worksheet = workbook.Sheets[workbook.SheetNames[0]]
  20.   const jsonData = utils.sheet_to_json(worksheet, { header: 1 })
  21.   
  22.   columns.value = jsonData[0]
  23.   excelData.value = jsonData.slice(1).map(row => {
  24.     return columns.value.reduce((obj, col, index) => {
  25.       obj[col] = row[index]
  26.       return obj
  27.     }, {})
  28.   })
  29. }
  30. </script>
复制代码

五、完备接口示例

5.1 上传接口(Node.js示例)

  1. // Express 路由
  2. app.post('/api/upload', (req, res) => {
  3.   const multer = require('multer')
  4.   const upload = multer({ dest: 'uploads/' })
  5.   
  6.   upload.single('file')(req, res, (err) => {
  7.     if (err) return res.status(500).json({ code: 500, message: '上传失败' })
  8.    
  9.     // 返回文件信息
  10.     res.json({
  11.       code: 200,
  12.       data: {
  13.         url: `/files/${req.file.filename}`,
  14.         originalname: req.file.originalname,
  15.         size: req.file.size
  16.       }
  17.     })
  18.   })
  19. })
复制代码
5.2 下载接口(Node.js示例)

  1. app.get('/api/download/:filename', (req, res) => {
  2.   const filePath = path.join(__dirname, 'uploads', req.params.filename)
  3.   
  4.   res.setHeader('Content-Type', 'application/octet-stream')
  5.   res.setHeader('Content-Disposition', `attachment; filename=${req.params.filename}`)
  6.   
  7.   const fileStream = fs.createReadStream(filePath)
  8.   fileStream.pipe(res)
  9. })
复制代码

六、注意事项


  • 安全验证:所有文件接口需举行身份验证
  • 文件大小限制:Nginx需设置client_max_body_size
  • 文件存储

    • 敏感文件不要存储在公开目录
    • 利用OSS云存储更佳

  • 预览安全

    • 防止XSS攻击(特别处理HTML文件)
    • 利用CSP内容安全策略


七、完备项目结构

  1. /src
  2. ├─api/
  3. │  └─file.ts       # 文件相关接口封装
  4. ├─components/
  5. │  └─FilePreview.vue # 文件预览组件
  6. ├─utils/
  7. │  ├─download.ts   # 下载工具函数
  8. │  └─validation.ts # 文件验证函数
复制代码

八、总结

本文全面而详尽地实现了多项关键功能,为开辟者提供了从前端到后端、从组件开辟到接口对接的全方位解决方案。起首,我们基于Element Plus这一流行的Vue3组件库,成功构建了一个高效且用户友好的文件上传组件。该组件不仅支持文件的快速上传,还提供了丰富的用户交互体验,如进度条表现、上传成功/失败提示等,极大地提升了用户的利用感受。
在文件处理方面,我们实现了Axios二进制流文件的下载功能。通过Axios的强大网络请求能力,我们可以或许轻松地从服务器获取二进制文件流,并将其保存到本地或举行进一步的处理。这一功能为文件的异步下载和动态处理提供了有力支持。
为了满足不同格式文件的预览需求,我们精心设计了一套PDF/Excel/图片多格式的预览方案。该方案可以或许自动辨认文件范例,并调用相应的预览组件举行展示。无论是常见的图片文件,还是复杂的PDF、Excel文档,都能在我们的系统中得到清晰、准确的预览结果。
此外,我们还提供了前后端完备接口示例,展示了怎样在Vue3前端与后端服务器之间举行高效的数据交互。通过具体的接口定义和示例代码,开辟者可以快速地理解并实现前后端的数据通讯,为项目标快速迭代和部署提供了有力保障。
最后,在生产情况注意事项部门,我们总结了在实际部署过程中大概碰到的标题及解决方案,如性能优化、安全性考虑等。这些名贵的经验分享将帮助开辟者更好地将项目从开辟情况迁移到生产情况,确保系统的稳定性和可靠性。综上所述,本文不仅提供了丰富的功能实现,还为开辟者提供了全面的开辟指导和实战经验分享。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

惊雷无声

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表