Web端录屏方案调研

18 阅读3分钟

话不多说,直接上方案~

方案对比

方案star实现成本原理特点live demo
原生API-调用getDisplayMedia和MediaRecorder,手动管理流和数据块如果需要实现区域录屏,需要canvas绘制如果需要区域录屏、将录屏文件转为GIF,需要额外开发
RecordRTC6.7k需二次封装封装MediaRecorder自动合并数据块生成完整视频;支持webm→mp4转换(需集成FFmpeg.js);兼容旧版浏览器(通过adapter.js)如果需要区域录屏、将录屏文件转为GIF,需要额外开发www.webrtc-experiment.com/RecordRTC/s…Screen RecordingRecord Cropped Screen

文件转GIF,可使用 gif.js

技术方案

原生API方案(无第三方依赖)

实现方式:直接调用getDisplayMediaMediaRecorder,手动管理流和数据块。

核心代码(React示例):

import React, { useState, useRef } from 'react';
import { Button, Modal } from 'antd';
const NativeScreenRecorder = () => {
  const [isRecording, setIsRecording] = useState(false);
  const [previewUrl, setPreviewUrl] = useState('');
  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
  const chunksRef = useRef<BlobPart[]>([]);
  const startRecording = async () => {
    try {
      // 获取屏幕流(含系统声音)
      const stream = await navigator.mediaDevices.getDisplayMedia({
        video: { cursor: 'always' },
        audio: { echoCancellation: false }
      });
      // 初始化MediaRecorder
      mediaRecorderRef.current = new MediaRecorder(stream);
      mediaRecorderRef.current.ondataavailable = (e) => chunksRef.current.push(e.data);
      mediaRecorderRef.current.onstop = () => {
        const blob = new Blob(chunksRef.current, { type: 'video/webm' });
        const url = URL.createObjectURL(blob);
        setPreviewUrl(url);
        stream.getTracks().forEach(track => track.stop()); // 释放资源
      };
      mediaRecorderRef.current.start();
      setIsRecording(true);
    } catch (err) {
      console.error('录屏启动失败:', err);
    }
  };
  const stopRecording = () => {
    mediaRecorderRef.current?.stop();
    setIsRecording(false);
    chunksRef.current = []; // 清空数据块
  };
  return (
    <div>
      <Button onClick={startRecording} disabled={isRecording}>开始录屏</Button>
      <Button onClick={stopRecording} disabled={!isRecording} danger>结束录屏</Button>

      <Modal
        visible={!!previewUrl}
        title="录制预览"
        onCancel={() => {
          URL.revokeObjectURL(previewUrl);
          setPreviewUrl('');
        }}
      >
        <video src={previewUrl} controls autoPlay style={{ width: '100%' }} />
      </Modal>
    </div>
  );
};

优缺点:

优点缺点
无第三方依赖,体积小需手动处理流管理、错误捕获
支持最高质量录制(原始流)仅支持WebM格式
完全控制录制流程系统声音录制需用户手动启用实验功能

RecordRTC

功能:封装MediaRecorder,支持屏幕/摄像头/音频录制,提供pause/resume/格式转换等功能。

核心特性:

  • 自动合并数据块生成完整视频;

  • 支持webmmp4转换(需集成FFmpeg.js);

  • 兼容旧版浏览器(通过adapter.js)。

示例代码:

import RecordRTC from 'recordrtc';
const startRecording = async () => {
  const stream = await navigator.mediaDevices.getDisplayMedia({ video: true });
  const recordRTC = new RecordRTC(stream, {
    type: 'video',
    mimeType: 'video/webm',
    disableLogs: true
  });
  recordRTC.startRecording();
  // 停止录制并获取视频
  const stop = () => {
    recordRTC.stopRecording(() => {
      const videoBlob = recordRTC.getBlob();
      const videoUrl = URL.createObjectURL(videoBlob);
      // 预览或下载...
    });
    stream.getTracks().forEach(track => track.stop());
  };
};

优缺点:

优点缺点
简化流管理和数据处理依赖外部库(~30KB)
支持格式转换(需FFmpeg)最新浏览器特性支持滞后

面临的挑战

性能与资源问题

问题场景具体表现解决方案
长时间录制内存溢出- 数据块(chunks)积累导致内存占用过高- 浏览器崩溃或录制卡顿- 分段录制(每5分钟生成一个文件)- 使用WritableStream实时写入磁盘- 实现内存监控与警告机制

用户体验问题

问题场景具体表现解决方案
录屏权限弹窗干扰- 每次录制都需用户手动授权- 缓存用户授权状态?(提供"记住此选择"选项)
操作反馈不直观- 录制中缺少明显状态指示- 暂停/继续操作不流畅- 提供快捷键支持

开发挑战

问题场景具体表现解决方案
API复杂度高- getDisplayMedia/MediaRecorder参数配置复杂- 状态管理困难优先使用成熟框架:如RecordRTC,避免重复造轮子

明确功能边界:根据目标用户需求,合理取舍功能

渐进式增强:先实现基础录屏功能,再逐步添加选区录制、编辑等扩展功能