视频上传管理实现方案
前端部分(Vue.js)
使用<input type="file">元素配合<video>标签实现基础上传和预览功能:
<template>
<div>
<input type="file" accept="video/*" @change="handleFileChange" />
<video v-if="videoUrl" :src="videoUrl" controls width="400"></video>
<button @click="uploadVideo" :disabled="!selectedFile">上传</button>
</div>
</template>
<script>
export default {
data() {
return {
selectedFile: null,
videoUrl: ''
}
},
methods: {
handleFileChange(event) {
this.selectedFile = event.target.files[0]
this.videoUrl = URL.createObjectURL(this.selectedFile)
},
async uploadVideo() {
const formData = new FormData()
formData.append('video', this.selectedFile)
try {
const response = await axios.post('/api/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
console.log('上传成功:', response.data)
} catch (error) {
console.error('上传失败:', error)
}
}
}
}
</script>
后端处理(示例使用Node.js)
创建Express路由处理视频上传:
const express = require('express')
const multer = require('multer')
const path = require('path')
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/videos/')
},
filename: function (req, file, cb) {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9)
cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname))
}
})
const upload = multer({
storage: storage,
limits: {
fileSize: 100 * 1024 * 1024 // 限制100MB
}
})
router.post('/upload', upload.single('video'), (req, res) => {
res.json({
success: true,
filePath: req.file.path
})
})
视频管理功能扩展
视频列表展示
创建视频列表组件显示已上传视频:
<template>
<div class="video-list">
<div v-for="video in videos" :key="video.id" class="video-item">
<video :src="video.url" controls width="300"></video>
<div class="video-actions">
<button @click="deleteVideo(video.id)">删除</button>
</div>
</div>
</div>
</template>
视频分块上传(大文件处理)
使用axios配合FormData实现分块上传:

async uploadChunks(file) {
const chunkSize = 5 * 1024 * 1024 // 5MB每块
const totalChunks = Math.ceil(file.size / chunkSize)
for (let i = 0; i < totalChunks; i++) {
const start = i * chunkSize
const end = Math.min(start + chunkSize, file.size)
const chunk = file.slice(start, end)
const formData = new FormData()
formData.append('chunk', chunk)
formData.append('chunkIndex', i)
formData.append('totalChunks', totalChunks)
formData.append('fileId', this.fileId)
await axios.post('/api/upload-chunk', formData)
}
await axios.post('/api/merge-chunks', {
fileId: this.fileId,
fileName: file.name
})
}
视频元数据管理
数据库模型设计(示例)
const mongoose = require('mongoose')
const videoSchema = new mongoose.Schema({
title: String,
description: String,
url: String,
duration: Number,
size: Number,
uploadDate: { type: Date, default: Date.now },
userId: mongoose.Schema.Types.ObjectId,
thumbnail: String
})
module.exports = mongoose.model('Video', videoSchema)
视频缩略图生成
使用ffmpeg生成视频缩略图:
const ffmpeg = require('fluent-ffmpeg')
function generateThumbnail(videoPath, thumbnailPath) {
return new Promise((resolve, reject) => {
ffmpeg(videoPath)
.screenshots({
timestamps: ['00:00:01'],
filename: 'thumbnail.png',
folder: thumbnailPath
})
.on('end', resolve)
.on('error', reject)
})
}
安全与优化措施
文件类型验证

前端和后端都应验证文件类型:
// 前端验证
const validTypes = ['video/mp4', 'video/webm', 'video/ogg']
if (!validTypes.includes(file.type)) {
alert('不支持的文件类型')
return
}
// 后端验证
const fileFilter = (req, file, cb) => {
const validTypes = ['video/mp4', 'video/webm', 'video/ogg']
if (validTypes.includes(file.mimetype)) {
cb(null, true)
} else {
cb(new Error('不支持的文件类型'), false)
}
}
上传进度显示
使用axios的onUploadProgress显示上传进度:
axios.post('/api/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
},
onUploadProgress: progressEvent => {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
)
this.uploadProgress = percentCompleted
}
})
响应式布局优化
使用CSS Grid或Flexbox实现响应式视频列表:
.video-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
}
.video-item {
border: 1px solid #ddd;
padding: 10px;
border-radius: 4px;
}
video {
max-width: 100%;
height: auto;
}