web 前端培训如何在 H5 网页中实现扫码功能
之前在做的项目中需要实现一个扫码录入的功能,具体效果就是在点击扫码按钮后调取摄像头,扫描条形码将解码后的数据填入到输入框中。相信这个功能在日常的手机使用中,是非常常用的,下面来看看我是如何一步一步踩坑实现的吧
内容抢先看
采用 Quagga 库实现遇到的问题和瓶颈
接入微信 SDK 的踩坑指北
最终解决方案
编辑
一、扫码初探 Quagga
第一次接触到扫码的业务,一切都是全新的,也不知道从哪里开始,先到各个社区搜索了一下
编辑
当时的搜索词大概是这样,得到结果就是利用 HTML5 中提供的 API 去实现,然后又看到了 Quagga,barCode 等库,在 npm 上查看了官方描述后,我觉得 Quagga 这个库可能更符合这个项目的需求,因此对 Quagga 进行了一番研究 Quagga_前端培训
编辑
这个库的使用并不难,首先需要引入 Quagga 这个库
yarn add quagga
由于我是在 React 项目下开发的,因此我们需要在 return 的 JSX 内 添加一个 DOM 节点,用来定制摄像头打开摄像头影像的投放区域
编辑
代码中的 yourElement 节点就是用来做摄像头的影像投放的
接下来,需要开始使用 Quagga ,大概就是调一下方法,配置一下解码方式,扫码区域,然后就能唤起摄像头,进行扫码,再处理一下扫码结果。由于初学,对它具体的代码书写还不是很熟悉,因此看老外敲了一晚的代码,并在一个大佬的 github 仓库内,找到了一个开源的扫码录入项目
编辑
看了看它的实现代码,然后开始了我的踩坑
首先我们需要初始化 Quagga
需要定制一下我们的解码方式,对于我们需要扫描的码是什么类型的,可以找个检测网站测一下,我的是 Code39 类型的
Quagga.init({
inputStream: {
name: "Live",
type: "LiveStream", // 方式
constraints: {
width: '790',
height: '490'
}, // 解码区域
numberOfWorkers: navigator.hardwareConcurrency,
target: document.querySelector('#barcodeScan') // 影像输出到的节点
},
locate: true,
decoder: {
readers: ["code_39_reader"] // 解码方式
}
}, function (err) {
if (err) {
return
}
Quagga.start() // 开启
})
Quagga.onDetected(this.onDetect)
当成功扫码后会调用 onDetected 方法,这就有点像生命周期一样,都是定义好的,我们可以在这个函数里接收到返回来的 result 获取到 codeResult 扫描结果_web前端培训
onDetect(res){
// console.log(res.codeResult.code)
Quagga.stop()
Quagga.offProcessed()
console.log(res.codeResult);
}
然后我们就可以开始疯狂的扫码,测试,经过了一晚上的测试,我发现它并不能像别人视频中那样流畅准确的进行解码,基本上输出的结果没几个是对的上的,因此此路行不通,开始萌生了放弃的想法,后来发现可以直接调取微信的扫码功能,来实现我们的需求,因此开始了微信 SDK 踩坑之路
编辑
二、大战微信 SDK
在经历了 quagga 的失利后,开始了捣鼓接入微信 SDK 来实现,首先我们需要引入 weixin-js-sdk ,这样我们就可以使用一些 wx 官方 API
比如这里需要使用到 scanQRcode 在这里我们调用这个 API,它接收一个配置对象,具体可以看官方文档比较重要的就是 needResult 它决定扫码的结果由谁来处理,如果是 0 ,则由微信处理
例如扫取一个快递码,它在扫描结束后会跳转到对应的页面去,这不是我们想要的,因此设置为 1,会直接返回扫描的结果,我们可以在 success 回调中获取到这个结果 resultStr ,这个 resultStr 是一个数组,第一项是扫码的类型,第二项是解码后的值,因此我们处理一下
wx.scanQRCode({
needResult: 1, // 默认为 0,扫描结果由微信处理,1 则直接返回扫描结果,
scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是一维码,默认二者都有
success: function (res) {
let result = res.resultStr.split(',')[1]; // 当 needResult 为 1 时,扫码返回的结果
},
fail: function (err) {
console.log('error');
console.log(err);
}
})
这样我们一个简单的扫码功能就写好了,真是很方便,只需要绑定到事件处理回调即可被调用。真的是这么简单吗?
由于我们使用的是微信开放能力,我们需要进行配置,采用官方提供的 wx.config
需要配置我们的 appId,以及一个签名还需要配置我们需要使用的 API
wx.config({
debug: false, // 开启调试模式,调用的所有 api 的返回值会在客户端 alert 出来,若要查看传入的参数,可以在 pc 端打开,参数信息会通过 log 打出,仅在 pc 端时才会打印。
appId, // 必填,公众号的唯一标识
timestamp, // 必填,生成签名的时间戳
nonceStr, // 必填,生成签名的随机串
signature,// 必填,签名
jsApiList: ["scanQRCode"] // 必填,需要使用的 JS 接口列表
});
签名这些配置项,需要后台哥哥返回,我们需要向后端传递我们当前的 url,用来生成掐灭
注意:一定是需要动态的,写死了会有 bug
这样我们调用接口,后端返回几个参数即可
const data = await getWxKey({ url: window.location.href.split('#')[0] })
这里有几个需要注意的问题
调取微信 API 需要使用 access_token 这个需要后端去获取,怎么解决我也不清楚,应该是通过 微信公众号的 addId 去申请的
向后端传递的 url ,是需要通过动态获取的,不然可能会有 invalid signature 签名错误的情况
在代码层面上,我们能做的就是这些了,前端的代码逻辑没有很多,都是 API 调用,完整代码如下
const openCamera = async () => {
const data = await getWxKey({ url: window.location.href.split('#')[0] })
const { appId, timestamp, nonceStr, jsKey: signature } = data.data
wx.config({
debug: false, // 开启调试模式,调用的所有 api 的返回值会在客户端 alert 出来,若要查看传入的参数,可以在 pc 端打开,参数信息会通过 log 打出,仅在 pc 端时才会打印。
appId, // 必填,公众号的唯一标识
timestamp, // 必填,生成签名的时间戳
nonceStr, // 必填,生成签名的随机串
signature,// 必填,签名
jsApiList: ["scanQRCode"] // 必填,需要使用的 JS 接口列表
});
wx.ready(() => {
wx.scanQRCode({
needResult: 1, // 默认为 0,扫描结果由微信处理,1 则直接返回扫描结果,
scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是一维码,默认二者都有
success: function (res) {
let result = res.resultStr.split(',')[1]; // 当 needResult 为 1 时,扫码返回的结果
form.setFieldsValue({ orderNumber: result })
},
fail: function (err) {
console.log(err);
}
})
})
}
但是写到这里,我们的扫码功能仍然是不可用的,我们还需要在微信公众平台来配置我们的接口域名,不然得到的会是
编辑
我们需要在微信公众平台配置 JS 接口安全域名
编辑
这样我们的问题就能迎刃而解,在配置安全域名的时候,注意访问的域名不要启动代理,不然会绑定不成功
文章来源于程序员成长指北
评论