找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2344

积分

0

好友

342

主题
发表于 2025-12-25 07:41:26 | 查看: 31| 回复: 0

在日常前端开发与协作中,将页面操作或功能演示录制为视频进行分享是一种常见需求。例如,在远程面试中向面试官展示项目,或是将一段复杂的用户操作流程存档。本文将详细介绍如何纯前端实现浏览器屏幕录制,并将生成的视频文件保存到本地。

核心API:navigator.mediaDevices

navigator.mediaDevices 是一个只读属性,它返回一个 MediaDevices 对象。该对象提供了访问连接媒体输入设备(如摄像头、麦克风)的能力,同时也包含了至关重要的屏幕共享接口。这为我们在Web端进行音视频处理提供了基础。

const media = navigator.mediaDevices;

我们可以在其原型链上找到 getDisplayMedia 方法,该方法用于获取用户的屏幕捕获流,是实现屏幕录制、视频会议等应用的关键。

获取屏幕捕获流

调用 getDisplayMedia 方法可以请求用户的屏幕共享权限。该方法接受一个配置对象,通常我们至少需要视频流。

navigator.mediaDevices.getDisplayMedia({ video: true });

由于这是一个异步操作,我们需要将其置于异步函数中,并通过用户交互(例如点击按钮)来触发。

<body>
  <button id="recordBtn">开始录制</button>
  <script>
    const button = document.querySelector('#recordBtn');
    button.addEventListener('click', async () => {
      // 请求屏幕共享权限并获取媒体流
      const stream = await navigator.mediaDevices.getDisplayMedia({
        video: true
      });
      // 获取流后,后续处理...
    });
  </script>
</body>

点击按钮后,浏览器会弹出权限请求窗口,用户选择需要共享的屏幕或窗口后,即可获得对应的 MediaStream 对象。

使用 MediaRecorder 进行录制

获得屏幕流之后,我们需要使用 MediaRecorder API 对其进行录制。MediaRecorder 是用于在浏览器中录制音频和视频的接口。

在创建实例前,最好检查浏览器对特定媒体格式的支持情况。可以通过 MediaRecorder.isTypeSupported() 方法来判断。

// 常见的支持类型
const mimeType = MediaRecorder.isTypeSupported('video/webm;codecs=h264')
  ? 'video/webm;codecs=h264'
  : 'video/webm'; // 回退方案

随后,使用获取到的媒体流和 MIME 类型初始化 MediaRecorder 实例。

const mediaRecorder = new MediaRecorder(stream, { mimeType: mimeType });

MediaRecorder 实例创建后,我们需要监听其事件来处理录制的数据:

  • dataavailable 事件:当有录制数据可用时触发,我们将数据块收集起来。
  • stop 事件:当录制停止时触发,此时我们将所有数据块合并并生成可下载的文件。
const recordedChunks = []; // 用于存储数据块

mediaRecorder.addEventListener('dataavailable', function(event) {
  if (event.data.size > 0) {
    recordedChunks.push(event.data);
  }
});

mediaRecorder.addEventListener('stop', () => {
  // 将所有数据块合并成一个 Blob 对象
  const blob = new Blob(recordedChunks, { type: recordedChunks[0].type });
  // 为 Blob 生成一个临时 URL
  const url = URL.createObjectURL(blob);
  // 创建一个隐藏的 <a> 标签并触发下载
  const a = document.createElement('a');
  a.href = url;
  a.download = 'screen-recording.webm'; // 设置下载文件名
  a.click();
  // 释放 URL 对象
  URL.revokeObjectURL(url);
});

最后,调用 mediaRecorder.start() 方法开始录制。停止录制则需调用 mediaRecorder.stop()

完整实现示例

以下是将所有步骤整合后的完整代码示例:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>前端屏幕录制Demo</title>
</head>
<body>
  <button id="recordBtn">开始录制</button>
  <button id="stopBtn" disabled>停止并保存</button>

  <script>
    const recordBtn = document.querySelector('#recordBtn');
    const stopBtn = document.querySelector('#stopBtn');
    let mediaRecorder;
    let recordedChunks = [];

    recordBtn.addEventListener('click', async () => {
      try {
        // 1. 获取屏幕流
        const stream = await navigator.mediaDevices.getDisplayMedia({
          video: { frameRate: 30 } // 可配置帧率
        });

        // 2. 确定支持的MIME类型
        const mimeType = MediaRecorder.isTypeSupported('video/webm;codecs=vp9')
          ? 'video/webm;codecs=vp9'
          : 'video/webm';

        // 3. 创建 MediaRecorder 实例
        mediaRecorder = new MediaRecorder(stream, { mimeType: mimeType });

        // 4. 处理数据
        mediaRecorder.ondataavailable = (event) => {
          if (event.data.size > 0) {
            recordedChunks.push(event.data);
          }
        };

        mediaRecorder.onstop = () => {
          const blob = new Blob(recordedChunks, { type: recordedChunks[0].type });
          const url = URL.createObjectURL(blob);
          const a = document.createElement('a');
          a.href = url;
          a.download = `recording_${Date.now()}.webm`;
          document.body.appendChild(a);
          a.click();
          document.body.removeChild(a);
          URL.revokeObjectURL(url);

          // 重置状态
          recordedChunks = [];
          stopBtn.disabled = true;
          recordBtn.disabled = false;
        };

        // 5. 开始录制
        mediaRecorder.start(100); // 每100ms触发一次 dataavailable 事件
        recordBtn.disabled = true;
        stopBtn.disabled = false;

        // 当用户手动停止共享屏幕时,也停止录制
        stream.getVideoTracks()[0].addEventListener('ended', () => {
          if (mediaRecorder.state === 'recording') {
            mediaRecorder.stop();
          }
        });

      } catch (err) {
        console.error('获取屏幕流失败:', err);
        alert('无法开始录制:' + err.message);
      }
    });

    stopBtn.addEventListener('click', () => {
      if (mediaRecorder && mediaRecorder.state === 'recording') {
        mediaRecorder.stop();
        // 停止所有轨道
        mediaRecorder.stream.getTracks().forEach(track => track.stop());
      }
    });
  </script>
</body>
</html>

扩展应用:直接在控制台运行

此功能的核心逻辑足够简洁,甚至可以适配到任何已有网页。你只需稍作修改,即可将代码粘贴到浏览器控制台中运行,实现“随时随地”录制当前标签页。

// 修改触发方式,例如点击页面任意位置开始
document.body.addEventListener('click', async () => {
  const stream = await navigator.mediaDevices.getDisplayMedia({ video: true });
  // ... 后续 MediaRecorder 代码同上
});

将上述修改后的代码复制到浏览器的开发者工具控制台,回车执行,然后点击页面任意位置,即可触发屏幕录制流程。这种基于 getDisplayMediaMediaRecorder 的方案,为Web应用带来了强大的原生屏幕捕获与录制能力,非常适合用于创建演示视频、问题反馈或在线教学等场景。要深入了解现代Web API的更多可能性,可以参考HTML/CSS/JS相关技术专题。




上一篇:Spring RequestContextHolder源码解析:线程上下文工作原理与异步陷阱
下一篇:C++高性能日志库实战指南:6天实现千万级QPS异步日志与无锁并发
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-11 14:19 , Processed in 0.238735 second(s), 37 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表