网页录屏的实现
要在 JavaScript 中实现屏幕录制,可以使用 navigator.mediaDevices.getDisplayMedia() 方法来获取屏幕的媒体流。然后,可使用 MediaRecorder 对象将媒体流录制为视频文件。
但该方法会在浏览器弹出一个授权窗口,让用户选择要分享的内容,这不可实现“无感知”。
前置知识点
canvas.captureStream(60) 是一个用于将 元素中的内容以视频流的形式捕获出来的方法。参数 60 表示视频的帧率为 60 帧每秒。这个方法可以用于创建一个实时的视频流,可以被用于 WebRTC 连接、录制视频等场景中。
new MediaRecorder 是Web API提供的一个用来录制音频和视频的接口。操作流程通常是这样的:首先获取音频/视频数据流,然后使用 new MediaRecorder 对象来录制这些数据流。然后,你可以监听 dataavailable 事件来获取录制的数据块,最后将这些数据块拼接在一起,保存为一个音频或视频文件。
页面
Canvas视频录制<main>
<div class="buttons">
<button class="start-btn">开始录制</button>
<button class="stop-btn">结束录制</button>
</div>
<div id="box">
<section class="content">
<h2>TODO LIST</h2>
<div class="background-div">
<button class="background-btn">切换背景颜色</button>
</div>
<div id="todo-form">
<input type="text" class="input-field" placeholder="输入待办事项">
<button type="submit" class="submit-btn">提交</button>
</div>
<div class="list"></div>
</section>
</div>
<img src="转存失败,建议直接上传图片文件 " alt="转存失败,建议直接上传图片文件" class="hidden">
</main>
<script src="<https://cdn.bootcss.com/html2canvas/0.5.0-beta4/html2canvas.min.js>" defer></script>
<script src="canvas.js" defer></script>
js部分
`
document.addEventListener('DOMContentLoaded', () => {
document.querySelector('.background-btn').addEventListener('click', () => {
document.querySelector('.content').style.background = colors[col];
col = (col + 1) % colors.length;
canvasFunction();
});
document.querySelector(".input-field").addEventListener("input", (event) => {
canvasFunction();
});
document.querySelector('.submit-btn').addEventListener('click', () => {
const text = document.querySelector('.input-field').value;
document.querySelector('.input-field').value = '';
const div = document.createElement('div');
div.setAttribute('class', 'item');
div.innerText = text;
document.querySelector('.list').appendChild(div);
canvasFunction();
});
const box = document.getElementById('box');
const boxBoundingClientRect = box.getBoundingClientRect();
const w = boxBoundingClientRect.width;
const h = boxBoundingClientRect.height;
const canvas = document.createElement('canvas');
canvas.setAttribute('id', 'canvas');
canvas.setAttribute('width', w);
canvas.setAttribute('height', h);
canvas.style.display = 'none';
box.appendChild(canvas);
const img = document.querySelector('img');
const ctx = canvas.getContext("2d");
const allChunks = [];
const stream = canvas.captureStream(60); // 60 FPS recording 1秒60帧
const recorder = new MediaRecorder(stream, {
mimeType: 'video/webm;codecs=vp9'
});
// recorder.ondataavailable 是一个事件处理程序,用于监听录音或录制视频时,每次有新的数据块可用时触发的事件。
// 当录制媒体时,MediaRecorder 类会定期将数据存储为一个 Blob 对象并触发该事件。
// 你可以通过监听这个事件来获取这些数据块,并在录制结束后将它们合并成一个完整的音频或视频文件。
recorder.ondataavailable = (e) => {
console.log('监听流', e)
allChunks.push(e.data);
};
// 开始
document.querySelector('.start-btn').addEventListener('click', () => {
if (MediaRecorder.isTypeSupported('video/webm;codecs=vp9')) {
canvasFunction();
console.log("开始");
// recorder.start 是 MediaRecorder 对象的方法,用于开始录制音频或视频。
// 当你调用这个方法时,MediaRecorder 对象会开始接收来自音频或视频输入的数据,
// 并且在接收到数据后触发 dataavailable 事件。
recorder.start(10);
}
});
// 结束
document.querySelector('.stop-btn').addEventListener('click', () => {
console.log("结束录制");
canvasFunction();
setTimeout(() => {
console.log("保存");
recorder.stop();
const fullBlob = new Blob(allChunks);
const videoUrl = window.URL.createObjectURL(fullBlob);
const video = document.createElement('video');
video.controls = true;
video.src = videoUrl;
video.muted = true;
video.autoplay = true;
document.body.appendChild(video);
}, 1000);
});
const canvasFunction = () => {
console.log("html2canvas ", html2canvas)
html2canvas(box).then(canvas => {
const imgStr = canvas.toDataURL("image/png");
img.src = imgStr;
img.onload = function () {
ctx.drawImage(img, 0, 0, w, h);
}
});
}
});
`
弊端
使用html2canvas可能会对浏览器的性能造成一定的影响,特别是在处理大量或复杂的DOM元素时。这是因为html2canvas会遍历DOM树,并对每个元素进行渲染和截图处理。因此,如果页面包含大量复杂的内容,或者需要截取大尺寸的区域,可能会导致内存占用增加和CPU负载升高。
为了减少性能消耗,可以尝试以下方法:
- 仅对需要截取的局部进行截图,而不是整个页面
- 在进行截图时,尽量减少页面上的复杂动画和变化
- 使用合适的配置选项,比如限制最大宽度和高度,或者关闭抗锯齿等选项
此外,在使用html2canvas时,最好在测试阶段对性能进行评估,确保在实际应用中不会对用户体验造成负面影响。
借助canvas去画网页内容,具体可参考 html2canvas ,实现方式为持续对用户访问的页面进行截图并上传到服务器。为了视频流畅,一秒中我们需要25张图,一张图300KB,也就是60秒产生的图片为440M,这么大的网络开销明显吃不消。