不能直接调用navigator.mediaDevices.getDisplayMedia就开始录屏,它仅弹窗选择屏幕源,必须配合MediaRecorder才能生成文件;调用需满足HTTPS/localhost环境、用户手势触发、权限未被拒绝三个硬性前提,否则报NotAllowedError或静默失败。

不能直接调用 navigator.mediaDevices.getDisplayMedia 就开始录屏——它只负责弹窗选屏幕,后续必须配 MediaRecorder 才能生成文件,且整个链路对环境、触发时机、MIME 类型都极其敏感。
getDisplayMedia 调用失败的三个硬性前提
不是代码写错,而是浏览器直接拦截:必须同时满足以下三点,否则立刻报 NotAllowedError 或静默失败。
- 页面运行在
https://或http://localhost下(file://协议、HTTP 域名、IP 地址直连均不通过) - 调用必须由用户手势触发,比如
click、touchend,不能在DOMContentLoaded、load或定时器里自动执行 - 用户首次拒绝后,再次调用不会重弹权限框;需引导用户手动进浏览器地址栏点锁形图标 → “网站设置” → 手动重置“屏幕捕获”权限
video: true 和 video: { mediaSource: 'screen' } 的行为差异
看似等价,实则影响用户可选范围和 Chrome 版本兼容性:
-
video: true:在 Chrome 92+ 中默认只显示“窗口”和“标签页”,不出现“整个屏幕”选项(尤其 macOS 上) -
video: { mediaSource: 'screen' }:强制唤出三级选择框(整个屏幕 / 应用窗口 / 浏览器标签页),是目前最稳妥的写法 -
audio: true不等于“录系统声音”——Chrome 不支持纯系统音频捕获;它只会额外请求麦克风权限,且最终是否包含音频,取决于用户在共享弹窗中是否勾选“包含音频”复选框(仅 Chromium 95+ 支持该 UI)
MediaRecorder 启动前必须确认 MIME 类型支持
MediaRecorder 在不同浏览器中对编码格式容忍度极低,硬写 video/mp4 在 Safari 和部分 Chrome 版本中会直接报 Failed to initialize MediaRecorder。
- 优先检测:
MediaRecorder.isTypeSupported('video/webm;codecs=vp9') - fallback 方案:
'video/webm;codecs=vp8'或无 codecs 的'video/webm'(但后者可能用上效率更低的编码器) - 不要依赖
onstart事件判断是否真正开始录制——它只是初始化完成;真正数据从ondataavailable开始产出,且首块可能为空,建议加if (event.data.size > 0)过滤
停止录制后必须手动 stop 所有轨道并释放 URL
很多人只调 mediaRecorder.stop(),却忘了清理源头,导致屏幕共享图标常驻任务栏、内存泄漏、下次调用失败。
- 停止录制后,务必遍历并
track.stop():stream.getTracks().forEach(t => t.stop()) -
URL.createObjectURL(blob)生成的 URL 必须在下载完成后立即调用URL.revokeObjectURL(url),否则 blob 持久驻留内存 - Safari 对
getDisplayMedia支持有限(仅 macOS 12.3+、iOS 16.4+),且不支持audio: true;若需跨平台,建议降级为仅录视频,并显式提示 Safari 用户“暂不支持系统音频”
最易被忽略的一点:用户关闭共享弹窗或切换 Tab 时,videoTrack 会触发 ended 事件,但此时 MediaRecorder 可能还没收到全部数据块。别只监听 ended 就调 stop(),应优先响应 mediaRecorder.onstop,再清理 track 和 URL。


















