You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 03:55:16