当前位置: 首页 > news >正文

Vue 中实现 PDF 文件上传

在 Vue 中实现 PDF 文件上传,核心是通过文件选择控件获取 PDF 文件,验证文件合法性(类型、大小等),再通过 axios 提交到后端接口。结合你的项目(使用 Element UI),以下是完整实现方案:

一、基础方案:使用 Element UI Upload 组件(推荐)

Element UI 的 el-upload 组件封装了文件选择、验证、上传等逻辑,使用简单且样式统一,适合快速集成。

1. 组件代码(单文件上传)
<template><div class="pdf-upload"><!-- 上传按钮 --><el-uploadclass="upload-demo"action="" <!-- 不直接用action,改为手动上传 -->:auto-upload="false" <!-- 关闭自动上传,手动触发 -->:on-change="handleFileChange" <!-- 文件选择变化时触发 -->:accept=".pdf" <!-- 限制只能选择PDF文件 -->:file-list="fileList" <!-- 已选择的文件列表 -->:limit="1" <!-- 限制只能上传1个文件 -->:on-exceed="handleExceed" <!-- 超过数量限制时触发 -->><el-button size="small" type="primary">选择 PDF 文件</el-button><div slot="tip" class="el-upload__tip">只能上传 PDF 格式文件,且大小不超过 10MB</div></el-upload><!-- 上传按钮 --><el-button size="small" type="success" @click="handleUpload" :disabled="!fileList.length">上传文件</el-button></div>
</template><script>
import api from '@/api' // 引入封装的axios接口export default {data() {return {fileList: [] // 存储选择的文件}},methods: {// 文件选择变化时触发(验证文件)handleFileChange(file, fileList) {this.fileList = fileList.slice(-1) // 只保留最后选择的1个文件(配合limit=1)// 验证文件类型if (file.raw.type !== 'application/pdf') {this.$message.error('请上传 PDF 格式的文件!')this.fileList = [] // 清空无效文件return false}// 验证文件大小(10MB = 10 * 1024 * 1024 bytes)const maxSize = 10 * 1024 * 1024if (file.size > maxSize) {this.$message.error('文件大小不能超过 10MB!')this.fileList = [] // 清空无效文件return false}},// 超过文件数量限制时触发handleExceed(files, fileList) {this.$message.warning(`最多只能上传 1 个 PDF 文件`)},// 手动触发上传async handleUpload() {if (!this.fileList.length) returnconst file = this.fileList[0].raw // 获取原生文件对象// 构造 FormData(文件上传必须用 FormData 格式)const formData = new FormData()formData.append('pdfFile', file) // 'pdfFile' 对应后端接口的参数名// 如需额外参数,可继续 append,例如:// formData.append('userId', 123)try {// 调用上传接口(需在 api 中定义)const res = await api.file.uploadPdf(formData)this.$message.success('文件上传成功!')console.log('上传结果:', res)// 上传成功后清空文件列表this.fileList = []} catch (error) {this.$message.error('文件上传失败,请重试!')console.error('上传错误:', error)}}}
}
</script><style scoped>
.pdf-upload {margin: 20px;
}
.el-upload__tip {margin-top: 10px;
}
</style>
2. 封装上传接口(src/api/file.js)
import request from '@/utils/request'export default {// 上传 PDF 文件uploadPdf(formData) {return request({url: '/api/file/upload-pdf', // 后端上传接口地址method: 'post',data: formData, // 直接传递 FormData 对象// 上传进度配置(可选)onUploadProgress: progressEvent => {const percent = Math.round((progressEvent.loaded / progressEvent.total) * 100)console.log(`上传进度:${percent}%`)// 可在这里更新进度条状态}})}
}

二、原生方案:使用 input [type=“file”](不依赖 UI 组件)

如果不使用 Element UI,可直接用原生 input 控件实现,核心逻辑一致:

<template><div class="native-upload"><input type="file" accept=".pdf" @change="handleFileSelect" class="file-input"><button @click="handleUpload" :disabled="!selectedFile">上传 PDF</button><p v-if="uploadProgress > 0 && uploadProgress < 100">上传中:{{ uploadProgress }}%</p></div>
</template><script>
import axios from 'axios'export default {data() {return {selectedFile: null,uploadProgress: 0}},methods: {// 选择文件handleFileSelect(e) {const file = e.target.files[0]if (!file) return// 验证文件类型if (file.type !== 'application/pdf' && !file.name.endsWith('.pdf')) {alert('请选择 PDF 格式文件!')e.target.value = '' // 清空选择return}// 验证文件大小(10MB)if (file.size > 10 * 1024 * 1024) {alert('文件大小不能超过 10MB!')e.target.value = ''return}this.selectedFile = file},// 上传文件async handleUpload() {if (!this.selectedFile) returnconst formData = new FormData()formData.append('pdfFile', this.selectedFile)try {const res = await axios.post('/api/file/upload-pdf', formData, {onUploadProgress: progress => {this.uploadProgress = Math.round((progress.loaded / progress.total) * 100)}})alert('上传成功!')this.selectedFile = nullthis.uploadProgress = 0} catch (error) {alert('上传失败!')console.error(error)}}}
}
</script><style>
.file-input {margin: 10px 0;
}
button {padding: 6px 12px;background: #42b983;color: white;border: none;border-radius: 4px;cursor: pointer;
}
button:disabled {background: #ccc;cursor: not-allowed;
}
</style>

三、关键注意事项

  1. 文件类型验证

    • 通过 file.type === 'application/pdf' 验证 MIME 类型,但部分环境可能不准确,建议同时检查文件名后缀 file.name.endsWith('.pdf')
  2. 文件大小限制:后端通常也会有大小限制,前端验证仅作为友好提示,需和后端保持一致(例如 10MB)。

  3. FormData 格式:文件上传必须使用 FormData 包装,且 axios 会自动设置 Content-Type: multipart/form-data不要手动设置此请求头(否则可能导致后端解析失败)。

  4. Electron 环境特殊处理

    • 如果需要直接读取本地文件路径(非通过 input 选择),可使用 Electron 的dialog.showOpenDialog选择文件:

      const { remote } = require('electron')
      const { dialog } = remote// 手动选择文件(不通过 input)
      async selectFileManually() {const result = await dialog.showOpenDialog({filters: [{ name: 'PDF Files', extensions: ['pdf'] }], // 只显示 PDFproperties: ['openFile']})if (!result.canceled) {const filePath = result.filePaths[0]// 读取文件并转换为 Blob 后上传(需用 fs 模块)const fs = require('fs')const fileBuffer = fs.readFileSync(filePath)const file = new Blob([fileBuffer], { type: 'application/pdf' })this.selectedFile = file}
      }
      

四、后端接口要求

后端接口需支持 multipart/form-data 类型请求,以 Node.js(Express)为例,需使用 multer 中间件处理文件:

const express = require('express')
const multer = require('multer')
const app = express()// 配置上传目录和文件名
const storage = multer.diskStorage({destination: (req, file, cb) => cb(null, 'uploads/'),filename: (req, file, cb) => cb(null, Date.now() + '-' + file.originalname)
})
const upload = multer({ storage,limits: { fileSize: 10 * 1024 * 1024 }, // 限制10MBfileFilter: (req, file, cb) => {// 后端再次验证文件类型if (file.mimetype !== 'application/pdf') {return cb(new Error('只允许上传 PDF 文件'))}cb(null, true)}
})// 上传接口
app.post('/api/file/upload-pdf', upload.single('pdfFile'), (req, res) => {res.json({code: 200,message: '上传成功',data: { filePath: req.file.path }})
})

通过以上方案,可在 Vue 中快速实现 PDF 文件上传功能,结合你的 Electron + Vue 项目场景,按需选择 Element 组件或原生实现即可。

http://www.dtcms.com/a/592593.html

相关文章:

  • 配置dns主从服务。要求从服务器能够定时从主服务器同步数据。
  • 中英文网站源码php网站开发8080无法访问此页面
  • 零基础如何在安服公司培训班成为网络安全工程师(黑客)
  • Oracle空间函数ST_AsText配置
  • 关系数据理论
  • 卫星姿态控制模式全解析:从基准到任务的体系化分类
  • 在百度seo快速收录要求是什么 有哪些
  • 一维前缀和与二维前缀和算法介绍及使用
  • Qwen多模态模型全解析
  • 做彩票网站要多少钱中山企业门户网站建设
  • 淘宝店铺全量商品接口实战:分类穿透采集与增量同步的技术方案
  • 【Linux】从基础到精通:内核调试与模块开发进阶之路
  • 高端品销售网站whois查询 站长工具
  • Diffusion Models与视频超分(3): 解读当前最快和最强的开源模型FlashVSR
  • 【Linux】进程间通信(二)命名管道(FIFO)实战指南:从指令操作到面向对象封装的进程间通信实现
  • 蒙古语网站建设网站制作 那种语言好
  • 阿里云效 = Jenkins + Gitlab + 免费服务器
  • Ganache-CLI以太坊私网JSON-RPC接口大全:从入门到精通
  • 免费测评RPC分布式博客平台(仅用云服务器支持高性能)
  • CentOS7 单机安装 Zookeeper 3.5.8(JDK 1.8 环境)
  • CMP(类Cloudera CDP 7.3 404版华为Kunpeng)与其他大数据平台对比
  • 青岛工程建设管理信息网站下载网站空间 购买
  • 25年11月软考架构真题《论云原生数据库》考后复盘总结
  • golang项目CRUD示例
  • 小米网站 用什么做的项城网站设计
  • Go语言数据竞争全面解析与解决方案
  • 重塑 exec.Command:打造更可控的 Go 命令执行器
  • 【译】借助提示词、资源和采样,在 Visual Studio 中充分利用 MCP
  • 华为OD机试 双机位A卷 - 整理版本号 (JAVA Python C++ JS GO)
  • 【C++初阶】vector容器的模拟实现,各接口讲解