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

若依框架实战:手把手教你搞定视频上传与预览(Vue3 + Element Plus版)

若依框架实战:Vue3+Element Plus视频上传与预览全流程解析

在Vue技术栈升级浪潮中,若依框架(Ruoyi)作为企业级快速开发平台,其Vue3+Element Plus版本带来了显著的性能提升和开发体验优化。本文将深入探讨如何基于新版技术栈实现视频上传与预览功能,解决开发者在迁移过程中遇到的实际问题。

1. 环境准备与项目配置

1.1 初始化若依Vue3项目

首先确保已安装Node.js 16+版本,然后通过以下命令创建项目:

npm init vue@latest ruoyi-vue3-video --template vue-ts cd ruoyi-vue3-video npm install

安装Element Plus及相关依赖:

npm install element-plus @element-plus/icons-vue axios

1.2 配置基础请求模块

src/utils/request.ts中配置axios实例:

import axios from 'axios' import { getToken } from '/@/utils/auth' const service = axios.create({ baseURL: import.meta.env.VITE_APP_BASE_API, timeout: 5000 }) service.interceptors.request.use(config => { if (getToken()) { config.headers['Authorization'] = 'Bearer ' + getToken() } return config })

2. 视频上传组件重构

2.1 Composition API实现核心逻辑

使用Vue3的setup语法糖重构上传逻辑:

<script setup lang="ts"> import { ref } from 'vue' import { ElMessage } from 'element-plus' import { getToken } from '/@/utils/auth' const uploadUrl = import.meta.env.VITE_APP_BASE_API + '/common/upload' const headers = { Authorization: 'Bearer ' + getToken() } const videoUrl = ref('') const uploadProgress = ref(0) const isUploading = ref(false) const beforeUpload = (file: File) => { const validTypes = ['video/mp4', 'video/ogg', 'video/webm'] const isLt50M = file.size / 1024 / 1024 < 50 if (!validTypes.includes(file.type)) { ElMessage.error('仅支持MP4/OGG/WEBM格式') return false } if (!isLt50M) { ElMessage.error('视频大小不能超过50MB') return false } isUploading.value = true return true } const handleProgress = (event: ProgressEvent) => { uploadProgress.value = Math.round((event.loaded / event.total) * 100) } const handleSuccess = (response: any) => { videoUrl.value = response.data.url isUploading.value = false uploadProgress.value = 0 } </script>

2.2 模板结构优化

采用Element Plus的Upload组件实现更优雅的UI:

<template> <el-upload class="video-uploader" :action="uploadUrl" :headers="headers" :show-file-list="false" :before-upload="beforeUpload" :on-progress="handleProgress" :on-success="handleSuccess" > <video v-if="videoUrl" :src="videoUrl" controls class="video-preview" /> <el-icon v-else class="upload-icon"> <Plus /> </el-icon> <el-progress v-if="isUploading" type="circle" :percentage="uploadProgress" class="upload-progress" /> </el-upload> </template>

3. 后端接口适配与优化

3.1 文件上传接口调整

Spring Boot后端需要调整文件接收方式:

@RestController @RequestMapping("/common") public class FileUploadController { @PostMapping("/upload") public AjaxResult uploadFile( @RequestParam("file") MultipartFile file, HttpServletRequest request) { try { String originalName = file.getOriginalFilename(); String extension = originalName.substring(originalName.lastIndexOf(".")); if (!Arrays.asList(".mp4", ".ogg", ".webm").contains(extension)) { return AjaxResult.error("不支持的文件格式"); } String fileName = UUID.randomUUID() + extension; String filePath = RuoYiConfig.getUploadPath() + fileName; File dest = new File(filePath); file.transferTo(dest); String url = ServletUtils.getRequestBaseUrl(request) + "/profile/upload/" + fileName; return AjaxResult.success().put("url", url); } catch (Exception e) { return AjaxResult.error(e.getMessage()); } } }

3.2 跨域与文件大小配置

application.yml中添加配置:

spring: servlet: multipart: max-file-size: 50MB max-request-size: 50MB ruoyi: profile: /path/to/upload

4. 高级功能实现

4.1 视频预览优化

实现封面图生成与预览:

<script setup> import { ref, watch } from 'vue' const videoRef = ref<HTMLVideoElement | null>(null) const posterUrl = ref('') watch(videoUrl, (url) => { if (url) { generatePoster() } }) const generatePoster = () => { if (videoRef.value) { const canvas = document.createElement('canvas') canvas.width = 300 canvas.height = 200 const ctx = canvas.getContext('2d') videoRef.value.addEventListener('loadeddata', () => { ctx?.drawImage(videoRef.value, 0, 0, canvas.width, canvas.height) posterUrl.value = canvas.toDataURL('image/jpeg') }) } } </script>

4.2 分片上传实现

对于大文件上传,可采用分片上传策略:

const chunkSize = 5 * 1024 * 1024 // 5MB const uploadByChunks = async (file: File) => { const chunks = Math.ceil(file.size / chunkSize) const fileMd5 = await calculateFileMd5(file) for (let i = 0; i < chunks; i++) { const start = i * chunkSize const end = Math.min(file.size, start + chunkSize) const chunk = file.slice(start, end) const formData = new FormData() formData.append('file', chunk) formData.append('chunkNumber', i.toString()) formData.append('totalChunks', chunks.toString()) formData.append('identifier', fileMd5) await axios.post('/common/chunk-upload', formData, { headers: { 'Content-Type': 'multipart/form-data' } }) uploadProgress.value = Math.round(((i + 1) / chunks) * 100) } await axios.post('/common/merge', { filename: file.name, identifier: fileMd5, totalChunks: chunks }) }

5. 性能优化与错误处理

5.1 上传队列管理

实现并发控制和失败重试机制:

class UploadQueue { private maxConcurrent = 3 private queue: UploadTask[] = [] private activeCount = 0 add(task: UploadTask) { this.queue.push(task) this.run() } private async run() { if (this.activeCount >= this.maxConcurrent || this.queue.length === 0) { return } this.activeCount++ const task = this.queue.shift() try { await task.execute() } catch (error) { if (task.retryCount < 3) { task.retryCount++ this.queue.unshift(task) } else { console.error('Upload failed after retries') } } finally { this.activeCount-- this.run() } } }

5.2 类型安全增强

为上传组件添加完整的TypeScript类型定义:

interface UploadResponse { code: number msg: string data: { url: string name: string size: number } } interface UploadProgressEvent { loaded: number total: number percent?: number } interface UploadRequestOptions { action: string file: File filename: string headers?: Record<string, string> onProgress?: (event: UploadProgressEvent) => void onSuccess?: (response: UploadResponse) => void onError?: (error: Error) => void }

在项目实际部署中,我们发现视频格式检测不能仅依赖前端验证,后端必须进行二次校验。同时,对于移动端上传场景,建议增加压缩选项和网络状态检测功能。

http://www.jsqmd.com/news/690990/

相关文章:

  • RMBG-2.0抠图效果实测:发丝、耳垂、项链缝隙处理展示
  • 安全测试与开发必备:在Kali和Windows 10上配置Proxychains4的保姆级避坑指南
  • 2026年评价高的汽车改装装脚垫/汽车改装装踏板/新能源汽车改装/理想车汽车改装公司哪家好 - 行业平台推荐
  • FFM模型实战:用PaddlePaddle复现Criteo数据集上的Field-aware Factorization Machines
  • 诊断与修复:AJAX请求返回readyState:0, status:0的深度排查指南
  • 告别Windows自带文件管理器!Directory Opus保姆级配置教程(附主题包下载)
  • 2026年靠谱的汽车改装装底盘护板/汽车改装装踏板/问界车汽车改装稳定供货厂家推荐 - 品牌宣传支持者
  • 别再乱设TPS了!JMeter常数吞吐量定时器5种模式实战对比(附避坑指南)
  • 告别SE93!用参数型事务码为SAP QUERY报表创建TCode的保姆级教程
  • Oumuamua-7b-RP多场景落地:轻小说作者辅助写作、Cosplay直播互动、日语播客脚本生成
  • 从RAW到DNG:利用rawpy.imread解锁专业图像处理流程(实战代码解析)
  • 【稀缺首发】华为OpenHarmony 4.1 + 华大半导体HC32L196联合验证报告:C语言跨域推理框架LiteLLM-Embed v1.2正式版API文档首曝
  • Keil MDK5.29安装与破解保姆级教程(附网盘链接,解决ARMCC许可证报错)
  • 2026年PVC电缆料造粒机TOP名录:TPU片材挤出机、水环造粒机、硅烷交联电缆料造粒机、ABS片材挤出机、ABS造粒机选择指南 - 优质品牌商家
  • Hail应用状态管理技术解析:Android系统级应用控制架构设计
  • 2026年高新区新能源汽车贴膜/汽车贴膜/康得新汽车贴膜厂家哪家好 - 行业平台推荐
  • C++20的char8_t来了,你的MSVC项目准备好迁移了吗?聊聊兼容性与/Zc:char8_t开关
  • 给RTOS新手的硬核科普:Cortex-M3/M4的双堆栈(MSP/PSP)到底在保护什么?
  • 告别性能噩梦:SAP ABAP 中处理海量数据时,如何用 SORT + LOOP FROM 拯救你的嵌套循环
  • 别再写if-else了!用C++正则表达式(regex)优雅解决密码合规检测问题
  • 别再折腾了!保姆级SecureCRT+SecureFX 9.x 一键安装与永久激活全攻略(附缺失文件解决方案)
  • 从崩溃到合规:C++高吞吐MCP网关安全性重构全流程,含OWASP ASVS 4.0全项对标及FIPS 140-3认证路径
  • 2026年口碑好的汽车贴膜贴车衣/汽车贴膜改装优质供应商推荐 - 品牌宣传支持者
  • Qwen3-TTS-Tokenizer-12Hz实用指南:支持多种音频格式,处理无忧
  • 从MPS面试题到实战:手把手教你用Verilog实现50%占空比的3分频器(附完整代码与波形分析)
  • 2026年热门的拓客工作手机系统/工作手机系统/业务管理工作手机系统/客户管理工作手机系统推荐榜单公司 - 行业平台推荐
  • 从预约到归档:医院IT运维眼中的PACS/RIS系统核心模块配置与避坑指南
  • 箱体类毕业设计
  • BDD2Seq:图神经网络优化可逆电路综合
  • 2026温州玻璃钢找哪家:温州导视牌、温州指示标牌、温州景观雕塑标识、温州标牌、温州标识标牌、温州标识牌、温州玻璃钢景观雕塑选择指南 - 优质品牌商家