如何在浏览器getUserMedia调取的摄像头流中添加QR码扫描矩形框
实现方案
核心思路是在摄像头视频流的上层叠加一层带镂空扫描框的半透明遮罩,无需修改摄像头流本身的处理逻辑,也不影响后续二维码识别功能。
1. 编写HTML结构
将视频标签和遮罩层放在同一个相对定位的父容器内,保证两者层级对齐:
<div class="scanner-container"> <video id="qr-video" autoplay playsinline></video> <div class="scan-mask"> <div class="scan-region"></div> <!-- 可选添加扫描动画线 --> <div class="scan-line"></div> </div> </div> <button>SCAN QR</button> <button>STOP QR</button>
2. 编写CSS样式
通过box-shadow实现外围半透明遮罩+中间镂空扫描框的效果:
/* 扫描容器,尺寸可根据需求自行调整 */ .scanner-container { position: relative; width: 100%; max-width: 450px; aspect-ratio: 4/3; overflow: hidden; margin: 12px 0; } /* 摄像头视频流适配 */ #qr-video { width: 100%; height: 100%; object-fit: cover; } /* 遮罩层 */ .scan-mask { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; } /* 扫描框 */ .scan-region { width: 220px; height: 220px; border: 2px solid #409eff; border-radius: 12px; /* 核心属性:用超大阴影实现外围半透明遮罩 */ box-shadow: 0 0 0 100vw rgba(0, 0, 0, 0.6); position: relative; } /* 扫描动画线,不需要可以删掉 */ .scan-line { position: absolute; top: 10px; left: 10px; right: 10px; height: 2px; background: #409eff; animation: scanMove 2s linear infinite; } @keyframes scanMove { 0% { top: 10px; } 100% { top: calc(100% - 12px); } }
3. 二维码识别逻辑适配(可选)
如果需要仅识别扫描框内的内容,减少无效识别率,可以用canvas裁剪扫描框对应区域的视频帧后再传给二维码识别库处理:
const video = document.getElementById('qr-video') const canvas = document.createElement('canvas') const ctx = canvas.getContext('2d') // 扫描框参数,需和CSS中定义的尺寸保持一致 const scanConfig = { width: 220, height: 220 } function scanQrCode() { // 按视频实际分辨率计算扫描框的坐标位置 const regionX = (video.videoWidth - scanConfig.width) / 2 const regionY = (video.videoHeight - scanConfig.height) / 2 // 裁剪扫描框区域的视频帧 canvas.width = scanConfig.width canvas.height = scanConfig.height ctx.drawImage(video, regionX, regionY, scanConfig.width, scanConfig.height, 0, 0, scanConfig.width, scanConfig.height ) const frame = ctx.getImageData(0, 0, scanConfig.width, scanConfig.height) // 此处将frame传入二维码识别库即可 requestAnimationFrame(scanQrCode) }
注意事项
- 移动端需要给video标签添加
playsinline属性,避免触发浏览器默认全屏播放行为 - 计算裁剪坐标时要使用
video.videoWidth和video.videoHeight的实际输出分辨率,不要用CSS设置的显示尺寸,避免裁剪区域错位 - 遮罩层不需要额外处理交互事件,不会影响视频流的正常运行
内容的提问来源于stack exchange,提问作者Venda 97
相关产品推荐
相关产品推荐

