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

如何使用React Hook创建浏览器录屏组件?

实现React浏览器屏幕录制组件的完整方案

核心依赖:浏览器原生API

实现屏幕录制主要依靠两个浏览器原生API:

  • MediaDevices.getDisplayMedia():用于请求用户授权并捕获屏幕/窗口/标签页的媒体流
  • MediaRecorder:用于将捕获到的媒体流编码为可保存的视频文件

组件实现步骤

  1. 请求屏幕捕获权限
    调用getDisplayMedia()获取屏幕流,需要处理用户拒绝授权的情况,同时注意该API只能在HTTPS环境或localhost下生效。

  2. 初始化MediaRecorder
    拿到媒体流后,创建MediaRecorder实例,指定输出格式(推荐video/webm,兼容性较好),监听dataavailable事件收集录制的片段数据。

  3. 处理录制控制逻辑
    实现开始、暂停、停止录制的函数,注意暂停后恢复录制的连续性,以及停止录制后将片段数据合并为完整的Blob文件。

  4. 生成下载链接
    录制结束后,将收集到的片段数据转为Blob,创建Object URL用于下载或预览。

  5. 清理资源
    组件卸载或停止录制时,必须关闭媒体流的所有轨道,销毁MediaRecorder实例,避免内存泄漏。

关键细节处理

  • 浏览器兼容性:先检测浏览器是否支持getDisplayMedia和MediaRecorder,不支持时给出友好提示
  • MIME类型兼容:可以通过MediaRecorder.isTypeSupported()检测当前浏览器支持的视频格式
  • 错误处理:捕获权限拒绝、录制中断等异常,及时反馈给用户
  • 状态管理:用React状态管理录制状态(未录制/录制中/暂停)、录制数据等

完整代码示例

import { useState, useRef, useEffect } from 'react';

const ScreenRecorder = () => {
  const [isRecording, setIsRecording] = useState(false);
  const [isPaused, setIsPaused] = useState(false);
  const [recordedChunks, setRecordedChunks] = useState([]);
  const [downloadUrl, setDownloadUrl] = useState('');
  const mediaRecorderRef = useRef(null);
  const streamRef = useRef(null);

  // 检测浏览器支持情况
  useEffect(() => {
    if (!navigator.mediaDevices?.getDisplayMedia || !window.MediaRecorder) {
      alert('当前浏览器不支持屏幕录制功能,请使用Chrome、Firefox等现代浏览器');
    }
  }, []);

  // 清理资源
  useEffect(() => {
    return () => {
      if (streamRef.current) {
        streamRef.current.getTracks().forEach(track => track.stop());
      }
      if (mediaRecorderRef.current) {
        mediaRecorderRef.current.stop();
      }
    };
  }, []);

  const startRecording = async () => {
    try {
      // 请求屏幕捕获
      const stream = await navigator.mediaDevices.getDisplayMedia({
        video: { displaySurface: 'monitor' },
        audio: false // 如需录制音频可改为true,注意部分浏览器需要额外授权
      });
      streamRef.current = stream;

      // 初始化MediaRecorder
      const mimeType = 'video/webm; codecs=vp9';
      const mediaRecorder = new MediaRecorder(stream, { mimeType });
      mediaRecorderRef.current = mediaRecorder;

      // 收集录制数据
      mediaRecorder.ondataavailable = (e) => {
        if (e.data.size > 0) {
          setRecordedChunks(prev => [...prev, e.data]);
        }
      };

      // 录制结束处理
      mediaRecorder.onstop = () => {
        const blob = new Blob(recordedChunks, { type: mimeType });
        const url = URL.createObjectURL(blob);
        setDownloadUrl(url);
        setRecordedChunks([]);
      };

      mediaRecorder.start();
      setIsRecording(true);
      setIsPaused(false);
    } catch (err) {
      console.error('录制启动失败:', err);
      alert('无法启动录制,请检查权限设置');
    }
  };

  const togglePause = () => {
    if (!mediaRecorderRef.current) return;
    if (isPaused) {
      mediaRecorderRef.current.resume();
      setIsPaused(false);
    } else {
      mediaRecorderRef.current.pause();
      setIsPaused(true);
    }
  };

  const stopRecording = () => {
    if (!mediaRecorderRef.current) return;
    mediaRecorderRef.current.stop();
    streamRef.current.getTracks().forEach(track => track.stop());
    setIsRecording(false);
    setIsPaused(false);
  };

  const downloadRecording = () => {
    if (!downloadUrl) return;
    const a = document.createElement('a');
    a.href = downloadUrl;
    a.download = `screen-recording-${Date.now()}.webm`;
    a.click();
    URL.revokeObjectURL(downloadUrl);
    setDownloadUrl('');
  };

  return (
    <div className="screen-recorder">
      <div className="controls">
        {!isRecording ? (
          <button onClick={startRecording}>开始录制</button>
        ) : (
          <>
            <button onClick={togglePause}>{isPaused ? '继续' : '暂停'}</button>
            <button onClick={stopRecording}>停止录制</button>
          </>
        )}
        {downloadUrl && <button onClick={downloadRecording}>下载录制文件</button>}
      </div>
      {downloadUrl && (
        <div className="preview">
          <h3>录制预览</h3>
          <video src={downloadUrl} controls width="600" />
        </div>
      )}
    </div>
  );
};

export default ScreenRecorder;

扩展功能建议

  • 添加音频录制支持:在getDisplayMedia中开启audio: true,部分浏览器可能需要同时捕获系统音频和麦克风,可结合getUserMedia实现
  • 支持录制特定窗口/标签页:修改getDisplayMedia的参数,displaySurface可选window或browser
  • 添加录制时长显示:通过定时器实时计算录制时间
  • 优化UI:添加录制状态指示器(如红色闪烁圆点)

内容的提问来源于stack exchange,提问作者Smith Mori

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 20:20:02