纯前端网页扫码三步实现:1. 用 getUserMedia 获取摄像头流并绑定 video 元素;2. 用 requestAnimationFrame 定时将视频帧绘制到 Canvas 并提取图像数据;3. 用 jsQR 将 RGBA 转灰度后解析 QR 码。

要在网页端用 Canvas 获取视频流并实现扫码解析,核心是三步:获取摄像头视频流、将帧画面绘制到 Canvas、用 JS 解码库(如 jsQR)分析图像数据。整个过程不依赖后端,纯前端完成。
1. 请求用户摄像头权限并播放视频流
使用 navigator.mediaDevices.getUserMedia() 获取视频流,绑定到 <video> 元素:
- 确保页面通过 HTTPS 或 localhost 访问(现代浏览器要求安全上下文)
- 设置
video元素的autoplay和playsinline(iOS 必需) - 监听
loadeddata事件,确认视频已可读取帧数据
示例代码片段:
<video id="video" autoplay playsinline></video>const video = document.getElementById('video');
navigator.mediaDevices.getUserMedia({ video: true })
.then(stream => { video.srcObject = stream; })
.catch(err => console.error("访问摄像头失败:", err));2. 将视频帧绘制到 Canvas 并提取像素数据
Canvas 是图像处理的“中转站”。需定时(如 requestAnimationFrame)把当前视频帧画到 Canvas,再用 ctx.getImageData() 获取 RGBA 像素数组:
立即学习“前端免费学习笔记(深入)”;
- Canvas 尺寸建议设为 320×240 或 480×360 —— 足够识别且性能友好
- 必须等视频触发
loadeddata后才开始绘制,否则 getImageData 会报错 - 为提升扫码速度,可降低采样频率(如每 100ms 处理一帧),避免过度计算
关键绘制逻辑:
<canvas id="canvas" width="320" height="240"></canvas>const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
<p>function drawFrame() {
if (video.readyState === video.HAVE_ENOUGH_DATA) {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
// 后续传给解码器
}
requestAnimationFrame(drawFrame);
}3. 使用 jsQR 解析二维码(支持 QR Code)
jsQR 是轻量、纯 JS 的二维码识别库,无需 WebAssembly 或服务端介入:
- 只支持 QR Code(不支持条形码如 Code128,如需多码制可用 QuaggaJS 或 zxing-js)
- 接收 Uint8ClampedArray 格式的灰度图像数据(需将 Canvas 的 RGBA 转为灰度)
- 识别成功返回
{ data: "xxx", location: {...} },可直接提取内容
集成示例:
// 将 imageData.data(RGBA)转为灰度 Uint8Array
function toGrayscale(imageData) {
const { data, width, height } = imageData;
const length = width * height;
const result = new Uint8Array(length);
for (let i = 0; i < length; i++) {
const r = data[i * 4];
const g = data[i * 4 + 1];
const b = data[i * 4 + 2];
result[i] = r * 0.299 + g * 0.587 + b * 0.114; // YUV 灰度公式
}
return result;
}
<p>// 在 drawFrame 中调用
const code = jsQR(toGrayscale(imageData), canvas.width, canvas.height);
if (code) {
console.log("扫码成功:", code.data);
// 触发自定义事件、填充表单、跳转链接等
}4. 实用优化与注意事项
真实项目中需考虑兼容性、性能和体验细节:
- 添加加载状态提示(如“正在启动摄像头…”),失败时显示友好错误(如“请检查摄像头权限”)
- 在手机上启用
video.setAttribute('playsinline', '')防止全屏播放中断扫码 - 扫码区域可叠加半透明蒙层 + 矩形框,引导用户对准,提升识别率
- 识别成功后暂停帧处理(clearAnimationFrame),防止重复触发;用户确认后再恢复
- 部分安卓浏览器对 getUserMedia 支持不稳定,可降级 fallback 到文件上传扫码



















