在 Web 端执行扫码操作时,近距离扫描小尺寸二维码却遭遇画面模糊、识别失败,这是许多开发者频繁遇到的棘手问题。其根本原因往往在于——摄像头未能正确对焦。本文将从技术实现层面,详细阐述如何借助 navigator.mediaDevices.getUserMedia 有效启用自动对焦(focusMode),并提供一套可直接落地的完整解决方案。
在基于 HTML5 的 Web 端 QR 码扫描应用中,摄像头无法自动对焦是导致小尺寸或近距离二维码识别率显著下降的核心瓶颈。尽管 MediaStreamTrack.applyConstraints() 支持配置 focusMode,但实际效果高度依赖于设备能力、浏览器兼容性以及约束设置的具体方式。直接在 getUserMedia 中写入 advanced: [{ focusMode: "continuous" }] 并不能保证生效,甚至可能被浏览器直接忽略,致使前期努力付诸东流。
正确启用自动对焦的核心步骤
-
优先获取媒体流,再动态施加约束
focusMode属于高级约束(Advanced Constraint),操作时需要掌握一定技巧。无法在getUserMedia中一次性完成设置,必须获取MediaStreamTrack后,单独调用track.applyConstraints()进行配置,且前提是——设备必须原生支持该约束。 -
验证设备对
focusMode的支持情况
在开始任何操作之前,请先检查运行环境。通过navigator.mediaDevices.getSupportedConstraints()确认当前浏览器是否支持focusMode,若此环节未通过,后续所有步骤均属徒劳。
const supported = na vigator.mediaDevices.getSupportedConstraints();
console.log('focusMode supported:', !!supported.focusMode); // 必须为 true
- 采用标准约束语法,规避
advanced嵌套
一个常见的陷阱需要留意:advanced写法已被废弃,且与现代规范不兼容。错误示例:{ advanced: [{ focusMode: "continuous" }] }。正确的做法是将其直接作为顶层约束项:
const focusConstraints = {
focusMode: { ideal: "continuous" } // 或 "auto"
};
await track.applyConstraints(focusConstraints);
完整可运行示例(修复版)
QR Scanner with Auto-Focus Initializing...
重要注意事项
- 硬件与系统限制:iOS Safari(截至 iOS 17)以及部分低端 Android 设备,从根本上不支持
focusModeAPI。即便约束设置完全正确,若底层缺乏物理对焦马达或驱动支持,一切努力仍属无效。在此情况下,务必引导用户手动调整距离,例如提示“请保持 20-40cm 距离”。 continuous并非实时追焦:focusMode: "continuous"仅表示摄像头会持续执行对焦,但其响应速度和精度完全取决于设备性能。部分设备甚至仅支持单次对焦("auto"),切勿期望它能像专业相机一样追踪二维码移动。- 避免过度约束:同时设置
width/height/frameRate/focusMode多项参数,极易导致applyConstraints()拒绝执行并返回OverconstrainedError。建议优先保障focusMode生效,其余参数交由浏览器自行适配,避免过度干预。 - 移动端适配要点:务必添加
标签,否则在 iOS 上可能引发显示异常。此外,视频元素应保留muted属性,以防止 iOS 自动静音机制导致autoplay失败。
总结
在 Web 端实现稳定可靠的自动对焦,绝非设置一个参数那么简单。它需要融合能力检测、分步约束、错误降级以及用户体验引导等多重环节,才能达到理想效果。尽管 GitHub 上多数开源扫码库并未封装对焦逻辑(主要因为设备依赖性过强且场景复杂),但通过上述标准化流程,在支持相应能力的设备上,小尺寸二维码的识别成功率可获得显著提升。若目标用户以 iOS 设备为主,建议同步考虑提供「手动对焦辅助线」UI,或借助 MediaStreamTrack.getSettings() 动态反馈当前对焦状态,从而构建更健壮、更友好的扫码体验。
