@zxing/library vs html5-qrcode vs jsqr vs qr-scanner vs qrcode-reader
Web 端二维码扫描库选型指南
@zxing/libraryhtml5-qrcodejsqrqr-scannerqrcode-reader类似的npm包:

Web 端二维码扫描库选型指南

@zxing/libraryhtml5-qrcodejsqrqr-scannerqrcode-reader 都是用于在浏览器中识别二维码的 JavaScript 库,但它们在架构设计、使用方式和适用场景上有显著差异。这些库的核心目标是将摄像头视频流或静态图像中的二维码内容解析出来,但实现方式不同:有的提供完整的 UI 组件,有的只提供底层解码能力,有的则专注于特定平台(如移动端)的优化。开发者需要根据项目对易用性、性能、控制粒度和兼容性的要求做出选择。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
@zxing/library02,90311.9 MB16824 天前Apache-2.0
html5-qrcode06,1342.63 MB4363 年前Apache-2.0
jsqr04,011-965 年前Apache-2.0
qr-scanner02,867524 kB118-MIT
qrcode-reader0283-179 年前Apache-2.0

Web 端二维码扫描库深度对比:@zxing/library、html5-qrcode、jsqr、qr-scanner 与 qrcode-reader

在现代 Web 应用中,扫码功能已成为常见需求 —— 从登录验证到支付确认,再到信息录入。面对多个开源选项,开发者常困惑于如何选择最适合的库。本文将从核心能力、使用方式、控制粒度和实际代码层面,深入比较五个主流二维码扫描库,帮助你做出明智的技术决策。

🚫 首要提醒:弃用包请勿使用

首先明确一点:qrcode-reader 已被官方弃用。其 npm 页面明确标注 "This package has been deprecated",GitHub 仓库也处于归档状态。这意味着它不再接收更新、安全修复或兼容性改进。任何新项目都应避免使用此包,转而选择其他活跃维护的替代品。

接下来,我们聚焦于四个仍在积极维护的库:@zxing/libraryhtml5-qrcodejsqrqr-scanner

🔍 核心定位:你是要“引擎”还是要“整车”?

理解这些库的本质差异,关键在于区分 底层解码引擎完整扫码组件

  • jsqr 是纯粹的 解码引擎:它只做一件事 —— 接收 RGBA 像素数组,返回解码结果。不处理摄像头、不渲染视频、不管理权限。
  • @zxing/library多功能解码引擎:支持 QR Code、EAN、UPC 等多种条码格式,提供解码器对象,但仍需你自行搭建视频流管道。
  • html5-qrcodeqr-scanner完整扫码组件:它们封装了从请求摄像头权限、渲染视频预览到连续扫描的全过程,提供简单 API 即可启动扫码。

示例:从零开始扫码需要多少代码?

jsqr(仅解码)

// 你需要自己获取图像数据(例如从 canvas)
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

// 调用 jsqr 解码
const code = jsQR(imageData.data, imageData.width, imageData.height);
if (code) {
  console.log('Found QR code:', code.data);
}

@zxing/library(需手动管理视频流)

import { BrowserMultiFormatReader } from '@zxing/library';

const codeReader = new BrowserMultiFormatReader();
const videoInputDevices = await codeReader.listVideoInputDevices();
const deviceId = videoInputDevices[0].deviceId;

// 手动将视频元素传入,并处理结果回调
codeReader.decodeFromVideoDevice(deviceId, 'videoElementId', (result, err) => {
  if (result) {
    console.log('Decoded:', result.getText());
  }
});

html5-qrcode(开箱即用)

import { Html5Qrcode } from 'html5-qrcode';

const html5QrCode = new Html5Qrcode('reader-container');

html5QrCode.start(
  { facingMode: 'environment' }, // 移动端后置摄像头
  { fps: 10, qrbox: { width: 250, height: 250 } },
  (decodedText) => {
    console.log('Scanned:', decodedText);
  }
);

qr-scanner(简洁 API)

import QrScanner from 'qr-scanner';

const video = document.createElement('video');
const qrScanner = new QrScanner(video, result => {
  console.log('Scanned:', result);
});

qrScanner.start(); // 自动请求权限并开始扫描

💡 关键区别:jsqr@zxing/library 要求你构建整个扫码流程;html5-qrcodeqr-scanner 则为你打包好了这一切。

📱 移动端体验:谁更懂手机?

在移动端,扫码体验受摄像头切换、对焦、性能影响极大。

  • html5-qrcode 显式支持 { facingMode: 'environment' },可直接调用后置摄像头,并允许通过 qrbox 限制扫描区域,减少误扫。它还处理了 iOS Safari 的一些兼容性问题。
  • qr-scanner 内置了针对移动设备的优化,包括自动请求高分辨率视频流,并利用 Web Worker 在后台解码,避免卡顿。其文档特别强调了移动端测试。
  • @zxing/library 虽然能工作,但你需要自己处理 facingMode 和分辨率设置,否则默认可能打开前置摄像头。
  • jsqr 完全不涉及设备层,移动端体验取决于你如何获取图像帧。

移动端最佳实践示例

html5-qrcode 正确配置后置摄像头

html5QrCode.start(
  { facingMode: 'environment' }, // 关键:指定后置
  { fps: 12, qrbox: 250 },
  onScanSuccess
);

qr-scanner 自动优化

// 默认尝试使用后置摄像头,并启用 worker
const qrScanner = new QrScanner(video, onScan, {
  highlightScanRegion: true,
  highlightCodeOutline: true
});

相比之下,使用 @zxing/library 时,你必须手动构造设备约束:

const constraints = { video: { facingMode: 'environment' } };
const devices = await navigator.mediaDevices.enumerateDevices();
// 还需筛选出 rear camera 的 deviceId...

⚙️ 控制粒度:你需要多细的掌控?

如果你的应用需要精细控制扫描行为(例如暂停/恢复、动态切换分辨率、自定义扫描区域),不同库的能力差异明显。

  • @zxing/library 提供最细粒度的控制:你可以随时停止解码器、更换视频源、调整解码提示(hints),甚至同时运行多个解码器。
  • html5-qrcode 提供 pause() / resume() 方法,并允许在启动后动态修改部分配置(如 fps),但无法在运行时更改扫描区域大小。
  • qr-scanner 支持 stop() / start(),并可通过 setCamera() 切换摄像头,但缺乏对解码参数的直接暴露。
  • jsqr 的控制完全由你掌握,因为你负责每一帧的输入。

动态暂停/恢复扫描示例

html5-qrcode

// 启动后
await html5QrCode.start(...);

// 暂停
await html5QrCode.pause();

// 恢复
await html5QrCode.resume();

qr-scanner

qrScanner.start(); // 开始
qrScanner.stop();  // 停止(不会释放摄像头)
qrScanner.destroy(); // 彻底清理

@zxing/library

let decoding = true;

codeReader.decodeFromVideoDevice(deviceId, 'video', (result, err) => {
  if (result && decoding) {
    console.log(result.getText());
    decoding = false; // 手动停止后续回调
    codeReader.reset(); // 清理解码器
  }
});

// 恢复需重新调用 decodeFromVideoDevice

🧪 性能与准确性:谁更快更准?

所有库底层都基于类似算法(如 ZXing 或 jsQR),但实现细节影响实际表现。

  • qr-scanner 因使用 Web Worker,主线程不会被阻塞,在低端设备上更流畅。
  • html5-qrcode 允许你通过 fps 限制帧率,平衡性能与电量消耗。
  • @zxing/library 性能取决于你如何控制解码频率(例如是否每帧都解码)。
  • jsqr 本身很快,但如果你在主线程高频调用,仍可能导致卡顿。

📌 实测建议:在目标设备上用真实二维码测试。某些库对模糊、倾斜或低光照下的二维码识别率更高,这往往取决于预处理逻辑(如二值化、滤波),而不仅是解码算法。

🛠️ 错误处理与调试

健壮的扫码功能必须妥善处理权限拒绝、设备无摄像头、解码失败等情况。

html5-qrcode 提供详细的错误回调:

html5QrCode.start(
  constraints,
  config,
  onSuccess,
  (errorMessage, error) => {
    if (error.name === 'NotAllowedError') {
      alert('请允许摄像头权限');
    }
  }
);

qr-scanner 抛出异常,需 try/catch:

try {
  await qrScanner.start();
} catch (e) {
  if (e.message?.includes('No suitable camera')) {
    alert('未找到摄像头');
  }
}

@zxing/library 在回调中传递 error 对象:

codeReader.decodeFromVideoDevice(deviceId, 'video', (result, err) => {
  if (err && !(err instanceof NotFoundException)) {
    console.error('Scan error:', err);
  }
});

jsqr 无错误概念 —— 如果无法解码,直接返回 null。

✅ 总结:如何选择?

场景推荐库理由
快速集成扫码功能,兼顾桌面和移动端html5-qrcodeAPI 简洁,文档完善,自动处理兼容性问题
需要最高性能(尤其移动端),且目标浏览器较新qr-scannerWeb Worker 支持,专为扫码优化
需要扫描多种条码(非仅 QR Code)@zxing/library支持 EAN、UPC、Code 128 等数十种格式
已有图像处理流程,只需 QR 解码jsqr极简、无依赖、纯函数式
新项目避免 qrcode-reader已弃用,无维护

💡 最终建议

  • 多数项目:从 html5-qrcode 开始。它平衡了易用性、功能和兼容性,能满足 90% 的需求。
  • 高性能优先:若目标用户主要在现代移动设备上使用,且扫码是核心功能,尝试 qr-scanner
  • 特殊需求:如需扫描商品条形码,或深度集成到复杂 UI 中,则投入时间学习 @zxing/library
  • 极简场景:如果只是偶尔解析一张上传的图片,jsqr 是最轻量的选择。

记住:没有“最好”的库,只有“最合适”你当前项目的工具。先明确需求,再动手编码。

如何选择: @zxing/library vs html5-qrcode vs jsqr vs qr-scanner vs qrcode-reader

  • @zxing/library:

    选择 @zxing/library 如果你需要一个功能全面、支持多种条码格式(不仅限于 QR Code)的底层解码库,并且愿意自行处理摄像头访问、视频流渲染和解码循环。它适合需要高度定制化扫码体验或集成到复杂应用架构中的场景,但学习曲线较陡,需熟悉其解码器生命周期管理。

  • html5-qrcode:

    选择 html5-qrcode 如果你希望快速集成一个开箱即用的扫码组件,支持自动处理摄像头权限、视频预览和连续扫描,同时兼顾桌面和移动端体验。它提供了简洁的 API 和良好的文档,适合大多数常规 Web 应用,尤其是对开发效率有较高要求的项目。

  • jsqr:

    选择 jsqr 如果你只需要最轻量级的 QR Code 解码能力,并且计划完全自主控制图像输入(例如从 canvas 或静态图片提取像素数据)。它不包含任何摄像头或 UI 逻辑,纯粹是一个解码函数,适合嵌入到已有图像处理流程中,或用于服务端(配合 canvas 实现)等特殊场景。

  • qr-scanner:

    选择 qr-scanner 如果你的项目主要面向现代浏览器,并且重视移动端扫码性能与准确性。它内置了 worker 支持以避免阻塞主线程,同时提供简单的 API 来启动摄像头扫描或解析静态图像。注意它依赖原生 getUserMedia,因此在旧版浏览器中可能无法使用。

  • qrcode-reader:

    不要在新项目中选择 qrcode-reader,因为该包已在 npm 上被官方标记为 deprecated(弃用),其 GitHub 仓库也已归档。建议评估其他活跃维护的替代方案,如 html5-qrcode@zxing/library

@zxing/library的README

ZXing

Looking for an actively maintained barcode scanning library with commercial support? Check out STRICH – Barcode Scanning for Web Apps.

Project in Maintenance Mode Only

[!WARNING] The project is in maintenance mode, meaning, changes are driven by contributed patches. Only bug fixes and minor enhancements will be considered. There is otherwise no active development or roadmap for this project. It is "DIY".

Attention

NOTE: While we do not have the time to actively maintain zxing-js anymore, we are open to new maintainers taking the lead.

What is ZXing?

ZXing ("zebra crossing") is an open-source, multi-format 1D/2D barcode image processing library implemented in Java, with ports to other languages.

Supported Formats

See Projects and Milestones for what is currently done and what's planned next. 👀

1D product1D industrial2D
UPC-ACode 39QR Code
UPC-ECode 93Data Matrix
EAN-8Code 128Aztec
EAN-13CodabarPDF 417
ITFMaxiCode (needs testing!)
RSS-14
RSS-Expanded (not production ready!)
Micro-QR (needs testing!)

Status

Maintainer wanted Greenkeeper badge

NPM version npm Contributors Commits to deploy

Maintainability Test Coverage

Demo

See Live Preview in browser.

Note: All the examples are using ES6, be sure is supported in your browser or modify as needed, Chrome recommended.

Installation

npm i @zxing/library --save

or

yarn add @zxing/library

Limitations

On iOS-Devices with iOS < 14.3 camera access works only in native Safari and not in other Browsers (Chrome,...) or Apps that use an UIWebView or WKWebView. This is not a restriction of this library but of the limited WebRTC support by Apple. The behavior might change in iOS 11.3 (Apr 2018?, not tested) as stated here

iOS 14.3 (released in december 2020) now supports WebRTC in 3rd party browsers as well 🎉

Browser Support

The browser layer is using the MediaDevices web API which is not supported by older browsers.

You can use external polyfills like WebRTC adapter to increase browser compatibility.

Also, note that the library is using the TypedArray (Int32Array, Uint8ClampedArray, etc.) which are not available in older browsers (e.g. Android 4 default browser).

You can use core-js to add support to these browsers.

In the PDF 417 decoder recent addition, the library now makes use of the new BigInt type, which is not supported by all browsers as well. There's no way to polyfill that and ponyfill libraries are way to big, but even if PDF 417 decoding relies on BigInt the rest of the library shall work ok in browsers that doesn't support it.

There's no polyfills for BigInt in the way it's coded in here.

Usage

// use with commonJS
const { MultiFormatReader, BarcodeFormat } = require('@zxing/library');
// or with ES6 modules
import { MultiFormatReader, BarcodeFormat } from '@zxing/library';

const hints = new Map();
const formats = [BarcodeFormat.QR_CODE, BarcodeFormat.DATA_MATRIX/*, ...*/];

hints.set(DecodeHintType.POSSIBLE_FORMATS, formats);

const reader = new MultiFormatReader();

const luminanceSource = new RGBLuminanceSource(imgByteArray, imgWidth, imgHeight);
const binaryBitmap = new BinaryBitmap(new HybridBinarizer(luminanceSource));

reader.decode(binaryBitmap, hints);

Contributing

See Contributing Guide for information regarding porting approach and reasoning behind some of the approaches taken.

Contributors

Special thanks to all the contributors who have contributed for this project. We heartly thankful to you all.

And a special thanks to @aleris who created the project itself and made available the initial QR code port.