如何使用React Hook创建浏览器录屏组件?
实现React浏览器屏幕录制组件的完整方案
核心依赖:浏览器原生API
实现屏幕录制主要依靠两个浏览器原生API:
MediaDevices.getDisplayMedia():用于请求用户授权并捕获屏幕/窗口/标签页的媒体流MediaRecorder:用于将捕获到的媒体流编码为可保存的视频文件
组件实现步骤
请求屏幕捕获权限
调用getDisplayMedia()获取屏幕流,需要处理用户拒绝授权的情况,同时注意该API只能在HTTPS环境或localhost下生效。初始化MediaRecorder
拿到媒体流后,创建MediaRecorder实例,指定输出格式(推荐video/webm,兼容性较好),监听dataavailable事件收集录制的片段数据。处理录制控制逻辑
实现开始、暂停、停止录制的函数,注意暂停后恢复录制的连续性,以及停止录制后将片段数据合并为完整的Blob文件。生成下载链接
录制结束后,将收集到的片段数据转为Blob,创建Object URL用于下载或预览。清理资源
组件卸载或停止录制时,必须关闭媒体流的所有轨道,销毁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
相关产品推荐
相关产品推荐

