
本文详解如何在 web 端通过 navigator.mediadevices.getusermedia 正确启用摄像头自动对焦(focusmode),解决近距离扫描小尺寸 qr 码时图像模糊、识别失败的核心问题。
本文详解如何在 web 端通过 navigator.mediadevices.getusermedia 正确启用摄像头自动对焦(focusmode),解决近距离扫描小尺寸 qr 码时图像模糊、识别失败的核心问题。
在基于 HTML5 的 Web 端 QR 码扫描应用中,摄像头无法自动对焦是导致小尺寸或近距离二维码识别率骤降的常见瓶颈。尽管 MediaStreamTrack.applyConstraints() 支持 focusMode,但其实际生效依赖于设备能力、浏览器兼容性与约束设置方式——直接在 getUserMedia 中写入 advanced: [{ focusMode: "continuous" }] 并不能保证生效,甚至可能被忽略。
✅ 正确启用自动对焦的关键步骤
先获取媒体流,再动态应用约束
focusMode 属于高级约束(Advanced Constraint),必须在获得 MediaStreamTrack 后,通过 track.applyConstraints() 单独设置,且需确保该约束已被设备支持。验证设备是否支持 focusMode
使用 navigator.mediaDevices.getSupportedConstraints() 检查当前环境是否支持 focusMode:
const supported = navigator.mediaDevices.getSupportedConstraints();
console.log('focusMode supported:', !!supported.focusMode); // 必须为 true
-
使用标准约束语法,避免嵌套 advanced
❌ 错误写法(advanced 已废弃,且不兼容现代规范):{ advanced: [{ focusMode: "continuous" }] }✅ 正确写法(直接作为顶层约束项):
const focusConstraints = { focusMode: { ideal: "continuous" } // 或 "auto" }; await track.applyConstraints(focusConstraints);
✅ 完整可运行示例(修复版)
<title>QR Scanner with Auto-Focus</title><meta charset="utf-8"><script src="https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js"></script><video id="video" width="640" height="480" autoplay muted></video><canvas id="canvas" width="640" height="480" style="display:none;"></canvas><p id="result">Initializing...</p>
<script>
const video = document.getElementById("video");
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const resultEl = document.getElementById("result");
async function initScanner() {
try {
// Step 1: 请求摄像头权限(仅视频)
const stream = await navigator.mediaDevices.getUserMedia({
video: {
facingMode: "environment",
width: { ideal: 1280 },
height: { ideal: 720 },
frameRate: { ideal: 15 }
}
});
video.srcObject = stream;
await video.play();
// Step 2: 获取视频轨道并检查 focusMode 支持
const track = stream.getVideoTracks()[0];
const supported = navigator.mediaDevices.getSupportedConstraints();
if (!supported.focusMode) {
resultEl.textContent = "⚠️ focusMode not supported on this device";
return;
}
// Step 3: 应用对焦约束(关键!)
try {
await track.applyConstraints({
focusMode: { ideal: "continuous" }
});
console.log("✅ Auto-focus enabled successfully");
} catch (e) {
console.warn("❌ Failed to set focusMode:", e.name, e.message);
// 降级尝试:部分 Android 设备需用 "auto"
try {
await track.applyConstraints({ focusMode: "auto" });
console.log("✅ Fallback to 'auto' mode");
} catch (e2) {
console.error("❌ Focus mode not available", e2);
}
}
// Step 4: 启动扫码循环
const scanInterval = setInterval(() => {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const code = jsQR(imageData.data, imageData.width, imageData.height, {
inversionAttempts: "dontInvert",
});
if (code) {
clearInterval(scanInterval);
resultEl.textContent = `✅ Scanned: ${code.data}`;
alert(`QR Code: ${code.data}`);
}
}, 500);
} catch (err) {
resultEl.textContent = `❌ Error: ${err.message}`;
console.error(err);
}
}
// 延迟启动,确保 DOM 加载完成
window.addEventListener("load", initScanner);
</script>
⚠️ 重要注意事项
- 硬件与系统限制:iOS Safari(截至 iOS 17)和部分低端 Android 设备不支持 focusMode API,即使约束设置成功,底层无物理对焦马达或驱动支持,仍无法实现光学对焦。此时应引导用户手动调整距离(如提示“请保持 20–40cm 距离”)。
- continuous ≠ 实时追焦:focusMode: "continuous" 仅表示持续对焦,但响应速度和精度取决于设备性能;部分设备仅支持单次对焦("auto")。
- 避免过度约束:同时设置 width/height/frameRate/focusMode 可能导致 applyConstraints() 拒绝执行(返回 OverconstrainedError)。建议优先保证 focusMode,其余参数交由浏览器自适应。
- 移动端适配:务必添加 ,并使用 muted 属性防止 iOS 自动静音导致 autoplay 失败。
✅ 总结
Web 端实现可靠对焦并非“设置即生效”,而是需结合能力检测、分步约束、错误降级与用户体验引导。虽然 GitHub 上多数开源扫码库未封装对焦逻辑(因其设备依赖性强),但通过上述标准化流程,可在支持设备上显著提升小码识别成功率。若目标用户以 iOS 为主,建议同步提供「手动对焦辅助线」UI 或调用 MediaStreamTrack.getSettings() 动态反馈当前对焦状态,构建更鲁棒的扫码体验。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











