在日常前端开发与协作中,将页面操作或功能演示录制为视频进行分享是一种常见需求。例如,在远程面试中向面试官展示项目,或是将一段复杂的用户操作流程存档。本文将详细介绍如何纯前端实现浏览器屏幕录制,并将生成的视频文件保存到本地。
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 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 代码同上
});
将上述修改后的代码复制到浏览器的开发者工具控制台,回车执行,然后点击页面任意位置,即可触发屏幕录制流程。这种基于 getDisplayMedia 和 MediaRecorder 的方案,为Web应用带来了强大的原生屏幕捕获与录制能力,非常适合用于创建演示视频、问题反馈或在线教学等场景。要深入了解现代Web API的更多可能性,可以参考HTML/CSS/JS相关技术专题。