Vue3音视频录制实战5分钟从零构建浏览器端录制功能1. 为什么选择浏览器原生API进行音视频录制现代浏览器已经内置了强大的多媒体处理能力。根据WebRTC技术标准我们可以直接调用getUserMedia和MediaRecorderAPI实现零依赖的音视频采集与录制。相比第三方库方案原生方案具有三大优势零依赖无需安装额外npm包减少项目体积高性能浏览器原生实现避免抽象层性能损耗兼容性好主流浏览器均已支持相关API提示Chrome、Firefox、Edge等现代浏览器均已完整支持相关APISafari需要iOS 14.5/macOS Big Sur版本2. 五分钟快速实现方案2.1 项目初始化首先创建一个干净的Vue3项目如已有项目可跳过此步npm init vuelatest video-recorder-demo cd video-recorder-demo npm install2.2 核心录制组件实现创建src/components/VideoRecorder.vue文件写入以下代码template div classrecorder-container video refpreview autoplay muted classpreview-video/video div classcontrols button clicktoggleRecording :disabled!isSupported {{ isRecording ? 停止录制 : 开始录制 }} /button a v-ifvideoUrl :hrefvideoUrl downloadrecording.webm下载视频/a /div /div /template script setup import { ref, onMounted } from vue const preview ref(null) const isRecording ref(false) const isSupported ref(false) const videoUrl ref() let mediaRecorder null let recordedChunks [] onMounted(() { checkSupport() }) const checkSupport () { isSupported.value !!( navigator.mediaDevices?.getUserMedia window.MediaRecorder ) } const toggleRecording async () { if (isRecording.value) { stopRecording() } else { await startRecording() } } const startRecording async () { try { const stream await navigator.mediaDevices.getUserMedia({ audio: true, video: true }) preview.value.srcObject stream mediaRecorder new MediaRecorder(stream, { mimeType: video/webm;codecsvp9 }) mediaRecorder.ondataavailable (e) { if (e.data.size 0) recordedChunks.push(e.data) } mediaRecorder.onstop () { const blob new Blob(recordedChunks, { type: video/webm }) videoUrl.value URL.createObjectURL(blob) recordedChunks [] } mediaRecorder.start(100) // 每100ms收集一次数据 isRecording.value true } catch (err) { console.error(录制失败:, err) } } const stopRecording () { mediaRecorder.stop() preview.value.srcObject.getTracks().forEach(track track.stop()) isRecording.value false } /script style scoped .recorder-container { max-width: 600px; margin: 0 auto; } .preview-video { width: 100%; background: #000; } .controls { margin-top: 1rem; display: flex; gap: 1rem; } /style2.3 组件使用在App.vue中引入组件script setup import VideoRecorder from ./components/VideoRecorder.vue /script template VideoRecorder / /template启动开发服务器npm run dev3. 进阶功能扩展3.1 录制参数配置可以通过修改getUserMedia和MediaRecorder的配置参数实现不同效果参数类型可选值说明video.width640, 1280等视频采集宽度video.height480, 720等视频采集高度video.frameRate15, 24, 30等视频帧率audio.sampleRate44100, 48000音频采样率mimeTypevideo/webm, video/mp4输出格式示例配置const stream await navigator.mediaDevices.getUserMedia({ audio: { sampleRate: 48000, echoCancellation: true }, video: { width: 1280, height: 720, frameRate: 30 } })3.2 录制状态管理建议使用Composition API管理复杂的录制状态const recordingState reactive({ isRecording: false, elapsedTime: 0, error: null, stats: { videoBitsPerSecond: 0, audioBitsPerSecond: 0 } }) // 在mediaRecorder.start()后添加 setInterval(() { if (recordingState.isRecording) { recordingState.elapsedTime 1 } }, 1000)4. 常见问题解决方案4.1 浏览器兼容性处理不同浏览器对视频编码的支持有所不同建议做特性检测function getSupportedMimeType() { const types [ video/webm;codecsvp9, video/webm;codecsvp8, video/webm;codecsh264, video/mp4;codecsh264 ] return types.find(type MediaRecorder.isTypeSupported(type)) || }4.2 移动端适配要点在移动设备上需要特别注意添加playsinline属性防止iOS全屏播放处理设备旋转事件考虑横竖屏不同分辨率需求video refpreview autoplay muted playsinline classpreview-video/video4.3 性能优化技巧降低分辨率移动端可适当降低采集分辨率帧率控制对话场景可降低至15-24fps关闭音频如不需要可关闭音频采集及时释放资源录制结束后调用track.stop()const stopRecording () { mediaRecorder.stop() // 释放所有媒体轨道 preview.value.srcObject.getTracks().forEach(track track.stop()) isRecording.value false }5. 实际应用案例5.1 在线教育答题讲解template div VideoRecorder startlogStartTime stopuploadRecording / div v-ifrecordingLog 本次录制时长{{ recordingLog.duration }}秒 文件大小{{ (recordingLog.size / 1024 / 1024).toFixed(2) }}MB /div /div /template5.2 用户反馈收集结合表单实现多媒体反馈const feedbackForm reactive({ text: , video: null, isRecording: false }) const submitFeedback async () { const formData new FormData() formData.append(text, feedbackForm.text) formData.append(video, feedbackForm.video) await fetch(/api/feedback, { method: POST, body: formData }) }5.3 产品演示录制添加画中画模式增强演示效果const enterPipMode async () { try { await preview.value.requestPictureInPicture() } catch (err) { console.error(画中画模式不支持:, err) } }