小元
博客
详情文字在这里缓缓展开
静候你翻开这一页

原生API实现屏幕录制和实时预览

基于原生JS实现屏幕录制以及实时预览。

屏幕录制和实时预览


   一 效果预览

1718852939033.gif


   二 初始准备

       1. 创建一个Video标签用来预览播放录制的画面

       2. 创建两个按钮分别用于开始录制和停止录制,并绑定对应事件

<template>
  <div>
    <h1>实时画面</h1>
    <video id="video" ref="vRef" autoplay="autoplay" controls muted></video>

    <button @click="startRecording">开始录制</button>
    <button @click="stopRecording">停止录制</button>
  </div>
</template>

<script setup>
import {ref} from "vue";

// 用于获取video节点
const vRef = ref(null);

// 开始
const startRecording = async () => {

}

// 停止
const stopRecording = () => {}

</script>


   三 屏幕录制

       修改开始事件,添加录屏弹窗选择、数据处理事件

       流程:调用getDisplayMdeia后用户界面弹窗选择需要被录屏的界面,当用户点击确认后,在Promise的resolve中返回一个包含音/视频的媒体流,使用MediaRecorder从获取到的媒体流中录取内容,并生成媒体文件,在ondataavailable中获取数据字节并缓存。

       getDisplayMedia文档

       MediaRecorder文档

let mediaRecorder;
let chunks = [];

const startRecording = async () => {

  if (!vRef.value) vRef.value = document.getElementById("video");

  navigator.mediaDevices.getDisplayMedia({
    video: { mediaSource: 'screen' }
  }).then((mediaStream) => {
    
    // 从媒体流中录制内容,并生成媒体文件
    mediaRecorder = new MediaRecorder(mediaStream);

    // 数据存储
    mediaRecorder.ondataavailable = (event) => {
      if (event.data.size > 0) {
        chunks.push(event.data);

      }
    }

    mediaRecorder.start();
  }).catch((err) => {
    console.log("errMsg:", err)
  })
}

       弹窗:

       1718854486074.png


   四 停止播放与播放视频

       修改停止播放和开始播放事件

       流程:当用户点击停止录屏后,录制结束,把chunks中存储的数据转换为Blod对象,并使用createObjectURL把Blod转换为一个可在本地预览播放的src资源。

       Blod文档

       createObjectURL文档

       修改开始事件中的ondataavailable,添加数据处理和播放事件

// 数据存储
mediaRecorder.ondataavailable = (event) => {
  if (event.data.size > 0) {
    chunks.push(event.data);
  
    const blob = new Blob(chunks, { type: 'video/webm' });
    const url = URL.createObjectURL(blob);
    vRef.value.src = url;
  }
}

       完善停止事件

const stopRecording = () => {
  if (mediaRecorder.state === 'recording') {
    mediaRecorder.stop();
  }
}

       点击停止后,在video标签中会开始播放录制的内容。


  五 完整代码

<template>
  <div>
    <h1>实时画面</h1>
    <video ref="vRef" id="video" autoplay="autoplay" controls muted></video>

    <button @click="startRecording">开始录制</button>
    <button @click="stopRecording">停止录制</button>
  </div>
</template>

<script setup>
import {ref} from "vue";

// 数据存储
let chunks = [];
let mediaRecorder;

const vRef = ref(null);

// 开始
const startRecording = async () => {
  if (!vRef.value) vRef.value = document.getElementById("video");

  navigator.mediaDevices.getDisplayMedia({
    video: { mediaSource: 'screen' }
  }).then((mediaStream) => {

    // 从媒体流中录制内容,并生成媒体文件
    mediaRecorder = new MediaRecorder(mediaStream);

    // 数据存储
    mediaRecorder.ondataavailable = (event) => {
      if (event.data.size > 0) {
        chunks.push(event.data);

        const blob = new Blob(chunks, { type: 'video/webm' });
        const url = URL.createObjectURL(blob);
        vRef.value.src = url;
      }
    }

    mediaRecorder.start();
  }).catch((err) => {
    console.log("errMsg:", err)
  })
}


// 停止
const stopRecording = () => {
  if (mediaRecorder.state === 'recording') {
    mediaRecorder.stop();
  }
}
</script>

<style>
video{
  width: 1200px;
  height: 600px;
  border: 1px solid red;
}
</style>


   六 实时预览

       实时预览在于对数据的实时处理和渲染,这里面最重要的就是给Video元素添加重要属性srcObject。

       首先移除字段chunks,添加字段mediaStream,改造开始事件。

let mediaStream;
const startRecording = async () => {
  if (!vRef.value) vRef.value = document.getElementById("video");

   try {
     mediaStream = await navigator.mediaDevices.getDisplayMedia({
       video: { mediaSource: 'screen' }
     });

     vRef.value.srcObject = mediaStream;
     mediaRecorder = new MediaRecorder(mediaStream);
     
     mediaRecorder.ondataavailable = (event) => {
       if (event.data.size > 0) {
         const blob = new Blob([event.data], { type: 'video/webm' });
         const url = URL.createObjectURL(blob);
         vRef.value.src = url;
       }
     };

     mediaRecorder.start();
   } catch {
     //
   }
}

       改造结束事件,添加停止屏幕分享流

const stopRecording = () => {
  if (mediaRecorder.state === 'recording') {
    mediaRecorder.stop();
    mediaStream.getVideoTracks()[0].stop();
  }
}

      到此就结束了,若文中有不对的地方请在评论区留言指正,感激不尽,若有其它建议或困惑也请在评论区留言讨论。

渝ICP备2024031078号-1
本网站一切内容不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
如无意中侵犯了企业或个人的知识产权等,请及时通过电子邮件(1102905617@qq.com)告知我,本网站将会给予删除。
最新公告
😊访客你好,很高兴你的到来,本博客仍在建设中,还有些许功能尚在开发中,最后祝你在此能有所收获。
💥小元博客第三代自2025年9月上线以来,2026/08/09日迎来了它的第三次更新本次更新内容如下:
1. 文章详情页样式变更,由原来的弹窗改为单独的页面。
2. 使用Nuxt对项目进行了SEO优化,优化了搜索引擎的抓取和索引。
3. 对验签进行了优化,降低了请求被误触发拦截的概率。
4. 移动端也正在稳步推进中,在不久的将来会与大家见面。
5. 修复了首页黄历节日不显示的问题,以及其它bug的修复。