如何在React-Native Web应用中录制视频?或实现摄像头连拍
解决React Native Web端摄像头录制/拍照问题
一、Web端10秒视频录制实现
react-native-camera这类原生库只适配Android/iOS,Web端直接用浏览器原生的MediaRecorder API就能实现视频录制,完全兼容React Native Web。
核心步骤与代码示例
import { useState, useRef, useEffect } from 'react'; const VideoRecorder = () => { const [isRecording, setIsRecording] = useState(false); const videoRef = useRef(null); const mediaRecorderRef = useRef(null); const streamRef = useRef(null); // 初始化摄像头并获取视频流 const initCamera = async () => { try { const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true // 不需要音频可设为false }); streamRef.current = stream; if (videoRef.current) { videoRef.current.srcObject = stream; } } catch (err) { console.error('摄像头权限请求失败:', err); } }; // 启动录制+10秒自动停止 const startRecording = () => { if (!streamRef.current) return; const mediaRecorder = new MediaRecorder(streamRef.current, { mimeType: 'video/webm; codecs=vp9' // Chrome/Firefox兼容,Safari可改用video/mp4 }); const chunks = []; mediaRecorder.ondataavailable = (e) => { if (e.data.size > 0) chunks.push(e.data); }; mediaRecorder.onstop = () => { const blob = new Blob(chunks, { type: 'video/webm' }); const videoUrl = URL.createObjectURL(blob); // 这里可将videoUrl用于预览、上传或保存 console.log('10秒录制完成:', videoUrl); }; mediaRecorderRef.current = mediaRecorder; mediaRecorder.start(); setIsRecording(true); // 10秒后自动停止 setTimeout(() => stopRecording(), 10000); }; const stopRecording = () => { if (mediaRecorderRef.current && isRecording) { mediaRecorderRef.current.stop(); setIsRecording(false); } }; // 组件挂载时初始化摄像头,卸载时释放资源 useEffect(() => { initCamera(); return () => { streamRef.current?.getTracks().forEach(track => track.stop()); }; }, []); return ( <div> <video ref={videoRef} autoPlay playsInline style={{ width: '300px', height: 'auto' }} /> <button onClick={isRecording ? stopRecording : startRecording}> {isRecording ? '停止录制' : '开始10秒录制'} </button> </div> ); }; export default VideoRecorder;
注意事项
- 必须在HTTPS环境下运行(localhost除外),否则浏览器会拒绝摄像头权限请求
- 不同浏览器支持的视频格式有差异,测试时可调整
mimeType参数 - 录制完成后记得用
URL.revokeObjectURL()释放内存(示例中未体现,可在后续处理时添加)
二、Web端连续拍摄多张照片实现
如果视频录制方案不满足需求,可通过canvas截取视频流帧的方式实现连续拍照,本质是定时捕获摄像头画面。
核心步骤与代码示例
import { useState, useRef, useEffect } from 'react'; const ContinuousCameraCapture = () => { const [isCapturing, setIsCapturing] = useState(false); const [capturedImages, setCapturedImages] = useState([]); const videoRef = useRef(null); const canvasRef = useRef(null); const streamRef = useRef(null); const captureIntervalRef = useRef(null); const initCamera = async () => { try { const stream = await navigator.mediaDevices.getUserMedia({ video: true }); streamRef.current = stream; if (videoRef.current) { videoRef.current.srcObject = stream; } } catch (err) { console.error('摄像头权限请求失败:', err); } }; // 启动连续拍照(示例:每1秒拍1张,共拍10张) const startCapture = () => { if (!streamRef.current || isCapturing) return; setIsCapturing(true); setCapturedImages([]); let captureCount = 0; captureIntervalRef.current = setInterval(() => { if (captureCount >= 10) { stopCapture(); return; } const video = videoRef.current; const canvas = canvasRef.current; if (!video || !canvas) return; // 同步canvas尺寸与视频画面 canvas.width = video.videoWidth; canvas.height = video.videoHeight; const ctx = canvas.getContext('2d'); ctx.drawImage(video, 0, 0, canvas.width, canvas.height); // 获取图片base64数据,可直接用于预览或转blob上传 const imageUrl = canvas.toDataURL('image/jpeg', 0.8); // 0.8为图片质量(0-1) setCapturedImages(prev => [...prev, imageUrl]); captureCount++; }, 1000); // 拍照间隔,单位毫秒 }; const stopCapture = () => { if (captureIntervalRef.current) { clearInterval(captureIntervalRef.current); setIsCapturing(false); } }; useEffect(() => { initCamera(); return () => { streamRef.current?.getTracks().forEach(track => track.stop()); stopCapture(); }; }, []); return ( <div> <video ref={videoRef} autoPlay playsInline style={{ width: '300px', height: 'auto' }} /> <canvas ref={canvasRef} style={{ display: 'none' }} /> <button onClick={isCapturing ? stopCapture : startCapture}> {isCapturing ? '停止拍照' : '开始连续拍照(10张)'} </button> <div style={{ marginTop: '20px' }}> <h3>已拍摄照片:</h3> {capturedImages.map((img, index) => ( <img key={index} src={img} style={{ width: '100px', height: 'auto', margin: '5px' }} /> ))} </div> </div> ); }; export default ContinuousCameraCapture;
注意事项
- 可通过调整
setInterval的时间参数控制拍照频率 - 如果需要上传图片,可将
toDataURL转为blob格式(用canvas.toBlob()方法),更适合文件上传场景
内容的提问来源于stack exchange,提问作者Sarthak Rastogi
相关产品推荐
相关产品推荐

