
本文介绍一种不依赖屏幕共享 api 的纯前端方案:通过 canvas 截取目标 div 的实时渲染画面并转为媒体流,结合 recordrtc 实现精准的区域视频录制,避免全屏选择干扰。
本文介绍一种不依赖屏幕共享 api 的纯前端方案:通过 canvas 截取目标 div 的实时渲染画面并转为媒体流,结合 recordrtc 实现精准的区域视频录制,避免全屏选择干扰。
在 Web 开发中,常有需求仅录制页面中某个动态区域(如图表容器、演示面板或交互式画布),而非整个屏幕或浏览器窗口。但 navigator.mediaDevices.getDisplayMedia() 本质是系统级屏幕捕获 API,必须由用户手动选择窗口/标签页,无法限定到 DOM 节点——这正是你遇到问题的根本原因。
正确的思路是:将目标 div 渲染为 Canvas 帧序列,再将其提升为可录制的 MediaStream。现代浏览器支持 canvas.captureStream() 方法,它能将 Canvas 的绘制内容实时封装为 MediaStream(含视频轨道),完美适配 RecordRTCPromisesHandler 等录制库。
✅ 推荐实现方案(兼容性良好,无需额外权限)
async function startRecording() {
const recorderBtn = document.getElementById('recorder'); // 确保按钮 ID 正确
recorderBtn.textContent = "Stop recording";
const targetDiv = document.getElementById('divToRecord'); // 替换为你的 div ID
if (!targetDiv) throw new Error('Target div not found');
// 创建离屏 canvas,尺寸与目标 div 一致(响应式需监听 resize)
const canvas = document.createElement('canvas');
const dpr = window.devicePixelRatio || 1;
canvas.width = targetDiv.clientWidth * dpr;
canvas.height = targetDiv.clientHeight * dpr;
canvas.style.width = `${targetDiv.clientWidth}px`;
canvas.style.height = `${targetDiv.clientHeight}px`;
const ctx = canvas.getContext('2d');
ctx.scale(dpr, dpr); // 高清适配
// 关键:捕获当前 div 快照(注意:仅支持同源、无跨域图片/iframe)
try {
await html2canvas(targetDiv, {
useCORS: true,
allowTaint: false,
logging: false
}).then(canvas => {
ctx.drawImage(canvas, 0, 0);
});
} catch (e) {
console.warn('html2canvas fallback failed, using basic drawImage');
ctx.fillStyle = '#fff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(targetDiv, 0, 0, targetDiv.clientWidth, targetDiv.clientHeight, 0, 0, canvas.width, canvas.height);
}
// 将 canvas 转为媒体流(帧率默认 30fps,可传参 captureStream(30))
const stream = canvas.captureStream(30);
const mediaRecorder = new RecordRTCPromisesHandler(stream, {
type: 'video',
mimeType: 'video/webm;codecs=vp9'
});
await mediaRecorder.startRecording();
// 示例:3秒后自动停止(实际项目中应由用户控制)
setTimeout(async () => {
await mediaRecorder.stopRecording();
const blob = await mediaRecorder.getBlob();
// 下载录制结果
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'recorded-div.webm';
a.click();
URL.revokeObjectURL(url);
recorderBtn.textContent = "Start recording";
}, 3000);
}
⚠️ 重要注意事项:
- 跨域限制:若 div 内含跨域图片或 iframe,drawImage 会触发 CORS 污染,导致 canvas 不可读。务必设置 img.crossOrigin = 'anonymous' 并确保服务端返回 Access-Control-Allow-Origin。
- 动态内容:上述代码仅录制单帧。如需录制动画/滚动/交互过程,需用 requestAnimationFrame 持续重绘 canvas(见进阶示例)。
- 性能优化:高频重绘建议限制帧率(如 24fps)、启用 will-change: transform 提升 canvas 渲染性能。
- 替代方案:对复杂场景(如 WebGL、Canvas 2D 动画),直接录制其原生 canvas 更高效,无需 html2canvas。
✅ 进阶:录制动态内容(推荐用于实时更新区域)
function startLiveRecording() {
const targetDiv = document.getElementById('divToRecord');
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
let animationId;
function renderLoop() {
// 清空并重绘(此处可集成 html2canvas 或自定义渲染逻辑)
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(targetDiv, 0, 0, targetDiv.clientWidth, targetDiv.clientHeight, 0, 0, canvas.width, canvas.height);
animationId = requestAnimationFrame(renderLoop);
}
const stream = canvas.captureStream(24);
const recorder = new RecordRTCPromisesHandler(stream, { type: 'video' });
recorder.startRecording();
renderLoop(); // 启动绘制循环
// 停止时清理
return () => {
cancelAnimationFrame(animationId);
recorder.stopRecording();
};
}
总结:录制特定 div 的核心在于「DOM → Canvas → MediaStream」的转换链路。它规避了 getDisplayMedia 的交互侵入性,赋予开发者完全的区域控制权。只要注意渲染兼容性与性能边界,即可在教育平台、代码演示、数据看板等场景中稳定落地。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










