原生API实现屏幕录制和实时预览
基于原生JS实现屏幕录制以及实时预览。
屏幕录制和实时预览
一 效果预览

二 初始准备
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中获取数据字节并缓存。
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)
})
}
弹窗:

四 停止播放与播放视频
修改停止播放和开始播放事件
流程:当用户点击停止录屏后,录制结束,把chunks中存储的数据转换为Blod对象,并使用createObjectURL把Blod转换为一个可在本地预览播放的src资源。
修改开始事件中的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();
}
}到此就结束了,若文中有不对的地方请在评论区留言指正,感激不尽,若有其它建议或困惑也请在评论区留言讨论。
