349 lines
8.7 KiB
Markdown
349 lines
8.7 KiB
Markdown
# scan-code-jssdk
|
||
|
||
统一扫码 JSSDK,支持桥接扫码、微信小程序、微信 JSSDK 扫码、Web 摄像头扫码、选择图片识别和扫码枪输入。
|
||
|
||
## 功能
|
||
|
||
- App 桥接环境:优先调用原生桥接 `startScan` / `stopScan`。
|
||
- 微信浏览器:初始化微信 JSSDK 后调用 `wx.scanQRCode`。
|
||
- Web 浏览器:使用 `BarcodeDetector` 识别二维码和条形码。
|
||
- 图片识别:选择本地图片后识别二维码/条形码。
|
||
- 扫码枪:监听键盘快速输入并统一走扫码监听回调。
|
||
- 监听规则:支持按 `match` 正则和 `level` 优先级分发扫码结果。
|
||
|
||
## 引入
|
||
|
||
构建后使用 `dist/index.js`:
|
||
|
||
```html
|
||
<script src="./dist/index.js"></script>
|
||
<script>
|
||
IScan.config().then(function () {
|
||
console.log("IScan ready");
|
||
});
|
||
</script>
|
||
```
|
||
|
||
如果脚本是后加载的,可以监听 `IScanReady`:
|
||
|
||
```js
|
||
function init() {
|
||
IScan.config().then(function () {
|
||
// ready
|
||
});
|
||
}
|
||
|
||
if (window.IScan) {
|
||
init();
|
||
} else {
|
||
window.addEventListener("IScanReady", init, { once: true });
|
||
}
|
||
```
|
||
|
||
## 快速开始
|
||
|
||
```js
|
||
IScan.config({
|
||
initWechatJssdk: {
|
||
apiUrl: "https://your-domain.com/wechat/jssdk-config"
|
||
}
|
||
}).then(function () {
|
||
// 监听识别状态
|
||
IScan.setStatusListener(function (status) {
|
||
console.log("status:", status);
|
||
});
|
||
// 监听识别结果
|
||
IScan.onScanListener(function (res) {
|
||
console.log("scan result:", res.result, res.key);
|
||
}, "scan", null, 100);
|
||
});
|
||
|
||
// 自动选择可用扫码方式:桥接 -> 微信 -> Web 摄像头 -> 图片识别
|
||
IScan.startScan();
|
||
|
||
// 仅打开 Web 视频扫码
|
||
IScan.scanVideo();
|
||
|
||
// 仅选择图片识别
|
||
IScan.scanImage();
|
||
|
||
// 停止当前扫码
|
||
IScan.stopScan();
|
||
```
|
||
|
||
## 配置项
|
||
|
||
通过 `IScan.config(options)` 配置。
|
||
|
||
```ts
|
||
interface ScanConfigOptions {
|
||
scanRestartDelay?: number,
|
||
bridgeEnabled?: boolean;
|
||
bridgeName?: string;
|
||
webScanEnabled?: boolean,
|
||
webScanCanvasEnabled?: boolean;
|
||
webScanCanvasStyle?: string;
|
||
webScanCloseButtonStyle?: string;
|
||
webScanCanvasClass?: string;
|
||
webScanCloseButtonClass?: string;
|
||
webScanType?: ("qrCode" | "barCode")[];
|
||
webScanVideoMirror?: boolean;
|
||
webScanVideoMirrorVertical?: boolean;
|
||
webScanImageFallbackOnVideoError?: boolean;
|
||
webScanVideoAccessTimeout?: number;
|
||
webScanVideoReadyTimeout?: number;
|
||
scanBeepAudio?: string;
|
||
scanBeepEnabled?: boolean;
|
||
initWechatJssdk?: {
|
||
apiUrl?: string;
|
||
sdkConfig?: {
|
||
debug?: boolean;
|
||
appId: string;
|
||
timestamp: number;
|
||
nonceStr: string;
|
||
signature: string;
|
||
};
|
||
sdkUrl?: string;
|
||
jsApiList?: string[];
|
||
};
|
||
}
|
||
```
|
||
|
||
| 配置 | 说明 | 默认值 |
|
||
| --- | --- | --- |
|
||
| `scanRestartDelay` | 扫码重启延迟,单位:毫秒 | `500ms` |
|
||
| `bridgeEnabled` | 是否启用桥接扫码 | `true` |
|
||
| `bridgeName` | 挂载在 `window` 上的桥接对象名称 | `__bridge_client__` |
|
||
| `webScanEnabled` | 是否支持 WebScan 扫码 | `true` |
|
||
| `webScanCanvasEnabled` | 是否显示 WebScan 扫码 canvas;关闭后仍会用隐藏 canvas 识别 | `true` |
|
||
| `webScanCanvasStyle` | WebScan 扫码 canvas 内联样式 | `position: fixed; width: 300px; height: 300px; top: 0; left: 0; z-index: 9999;` |
|
||
| `webScanCloseButtonStyle` | WebScan 关闭按钮内联样式(在默认位置上追加);按钮内容为 SVG,`path` 使用 `currentColor`,可通过按钮的 `color` 改图标颜色 | 圆形半透明底、白图标,定位在 canvas 右上角 |
|
||
| `webScanCanvasClass` | WebScan canvas 根元素 `class`,便于用外部样式表配合 `webScanCanvasStyle` 定制 | 无 |
|
||
| `webScanCloseButtonClass` | WebScan 关闭按钮 `class`,便于用外部样式表配合 `webScanCloseButtonStyle` 定制 | 无 |
|
||
| `webScanType` | WebScan 扫码类型 | `["qrCode", "barCode"]` |
|
||
| `webScanVideoMirror` | WebScan 视频是否水平镜像;不配置时自动判断:前置/PC 镜像,后置不镜像 | 自动 |
|
||
| `webScanVideoMirrorVertical` | WebScan 视频是否垂直镜像 | `false` |
|
||
| `webScanImageFallbackOnVideoError` | 摄像头不可用或打开失败时,是否自动弹出拍照/选图(适用于部分安卓内置浏览器) | `true` |
|
||
| `webScanVideoAccessTimeout` | 打开摄像头超时(毫秒),超时后走图片回退 | `10000` |
|
||
| `webScanVideoReadyTimeout` | 摄像头已开但无画面超时(毫秒),超时后走图片回退 | `8000` |
|
||
| `scanBeepAudio` | 扫码成功提示音地址(任意模式匹配成功时播放) | 内置提示音 |
|
||
| `scanBeepEnabled` | 扫码成功是否播放提示音 | `true` |
|
||
| `initWechatJssdk` | 微信 JSSDK 初始化配置,仅微信环境生效 | 无 |
|
||
|
||
`initWechatJssdk` 子配置:
|
||
|
||
| 配置 | 说明 | 默认值 |
|
||
| --- | --- | --- |
|
||
| `apiUrl` | 微信 JSSDK 签名配置接口地址;未传 `sdkConfig` 时会请求该接口,并自动携带当前页面 URL 参数 | 无 |
|
||
| `sdkConfig` | 直接传入微信 JSSDK 签名配置;配置后不再请求 `apiUrl` | 无 |
|
||
| `sdkConfig.debug` | 是否开启微信 JSSDK 调试模式 | `false` |
|
||
| `sdkConfig.appId` | 微信公众平台应用 ID | 必填 |
|
||
| `sdkConfig.timestamp` | 签名时间戳 | 必填 |
|
||
| `sdkConfig.nonceStr` | 签名随机字符串 | 必填 |
|
||
| `sdkConfig.signature` | 微信 JSSDK 签名 | 必填 |
|
||
| `sdkUrl` | 微信 JSSDK 脚本地址 | `https://res.wx.qq.com/open/js/jweixin-1.6.0.js` |
|
||
| `jsApiList` | 微信 JSSDK JS-API 列表,SDK 会自动追加 `scanQRCode` | `["scanQRCode"]` |
|
||
|
||
## 桥接接入
|
||
|
||
桥接对象需要挂载到 `window[bridgeName]`,并实现 `call(method, data)`。
|
||
|
||
SDK 会调用:
|
||
|
||
- `startScan`
|
||
- `stopScan`
|
||
|
||
异步回调方法名为 `${bridgeName}_handle_callback`。
|
||
|
||
```js
|
||
window.__bridge_client__ = {
|
||
call: function (method, data) {
|
||
var requestId = data.request_id;
|
||
|
||
if (method === "startScan") {
|
||
// 调用原生扫码后回调
|
||
window.__bridge_client___handle_callback({
|
||
code: 0,
|
||
method: method,
|
||
request_id: requestId,
|
||
payload: {
|
||
result: "https://example.com"
|
||
}
|
||
});
|
||
}
|
||
|
||
if (method === "stopScan") {
|
||
window.__bridge_client___handle_callback({
|
||
code: 0,
|
||
method: method,
|
||
request_id: requestId,
|
||
payload: {}
|
||
});
|
||
}
|
||
}
|
||
};
|
||
```
|
||
|
||
## 微信 JSSDK 接入
|
||
|
||
配置接口方式:
|
||
|
||
```js
|
||
IScan.config({
|
||
initWechatJssdk: {
|
||
apiUrl: "https://your-domain.com/wechat/jssdk-config"
|
||
}
|
||
});
|
||
```
|
||
|
||
接口会收到当前页面 URL 参数:`url=location.href.split("#")[0]`。
|
||
|
||
也可以直接传入微信签名配置:
|
||
|
||
```js
|
||
IScan.config({
|
||
initWechatJssdk: {
|
||
apiUrl: "",
|
||
sdkConfig: {
|
||
appId: "wx_app_id",
|
||
timestamp: 123456,
|
||
nonceStr: "nonce",
|
||
signature: "signature"
|
||
}
|
||
}
|
||
});
|
||
```
|
||
|
||
`jsApiList` 会默认追加 `scanQRCode`。
|
||
|
||
## API
|
||
|
||
### `config(options?): Promise<any>`
|
||
|
||
配置并初始化 SDK。
|
||
|
||
```js
|
||
IScan.config({
|
||
webScanCanvasEnabled: true,
|
||
webScanCanvasClass: "my-webscan-canvas",
|
||
webScanCloseButtonClass: "my-webscan-close"
|
||
});
|
||
```
|
||
|
||
### `setStatusListener(callback): void`
|
||
|
||
监听扫码状态,状态为:
|
||
|
||
- `scanning`
|
||
- `closed`
|
||
|
||
```js
|
||
IScan.setStatusListener(function (status) {
|
||
console.log(status);
|
||
});
|
||
```
|
||
|
||
### `onScanListener(callback, key, match?, level?): ScanListenerInfo`
|
||
|
||
添加扫码结果监听。
|
||
|
||
```js
|
||
var listener = IScan.onScanListener(function (res) {
|
||
console.log(res.result, res.key);
|
||
}, "order", "^https://", 100);
|
||
```
|
||
|
||
参数说明:
|
||
|
||
- `callback`:扫码结果回调。
|
||
- `key`:监听 key,同 key 会覆盖旧监听。
|
||
- `match`:可选正则字符串;扫码结果匹配后才回调。
|
||
- `level`:优先级,数值越大越先匹配。
|
||
|
||
### `offScanListener(callbackOrKey): void`
|
||
|
||
移除监听,可传 callback 或 key。
|
||
|
||
```js
|
||
IScan.offScanListener("order");
|
||
listener.cancel();
|
||
```
|
||
|
||
### `getStatus(): "scanning" | "ready"`
|
||
|
||
获取当前扫码状态。
|
||
|
||
```js
|
||
console.log(IScan.getStatus());
|
||
```
|
||
|
||
### `startScan(): void`
|
||
|
||
开启扫码。SDK 会按以下顺序选择可用能力:
|
||
|
||
1. 桥接扫码
|
||
2. 微信扫码
|
||
3. Web 摄像头扫码
|
||
4. 图片识别
|
||
|
||
扫码结果通过 `onScanListener` 回调。
|
||
|
||
```js
|
||
IScan.startScan();
|
||
```
|
||
|
||
### `scanVideo(): void`
|
||
|
||
直接开启 Web 摄像头扫码。扫码结果通过 `onScanListener` 回调。
|
||
|
||
```js
|
||
IScan.scanVideo();
|
||
```
|
||
|
||
### `scanImage(): void`
|
||
|
||
直接选择图片进行识别。识别结果通过 `onScanListener` 回调。
|
||
|
||
```js
|
||
IScan.scanImage();
|
||
```
|
||
|
||
### `stopScan(): void`
|
||
|
||
停止当前扫码。
|
||
|
||
```js
|
||
IScan.stopScan();
|
||
```
|
||
|
||
### `clear(): void`
|
||
|
||
清空全部扫码监听。
|
||
|
||
```js
|
||
IScan.clear();
|
||
```
|
||
|
||
## 类型
|
||
|
||
```ts
|
||
interface ScanResult {
|
||
result: string;
|
||
key: string;
|
||
}
|
||
|
||
type ScanStatus = "scanning" | "ready";
|
||
|
||
type ScanResultCallback = (result: ScanResult) => any;
|
||
type ScanStatusCallback = (status: ScanStatus) => any;
|
||
```
|
||
|
||
## 开发
|
||
|
||
```bash
|
||
npm install
|
||
npm run build
|
||
```
|
||
|
||
构建产物输出到 `dist` 目录。
|