如何優雅的在 H5 網頁中實現掃碼功能
之前在做的項目中需要實現一個掃碼錄入的功能,具體效果就是在點擊掃碼按鈕後調取攝像頭,掃描條形碼將解碼後的數據填入到輸入框中。相信這個功能在日常的手機使用中,是非常常用的,下面來看看我是如何一步一步踩坑實現的吧
💡 內容搶先看
-
採用
Quagga
庫實現遇到的問題和瓶頸 -
接入微信 SDK 的踩坑指北
-
最終解決方案
第一次接觸到掃碼的業務,一切都是全新的,也不知道從哪裏開始,先到各個社區搜索了一下
當時的搜索詞大概是這樣,得到結果就是利用 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
掃描結果
onDetect(res){
// console.log(res.codeResult.code)
Quagga.stop()
Quagga.offProcessed()
console.log(res.codeResult);
}
然後我們就可以開始瘋狂的掃碼,測試,經過了一晚上的測試,我發現它並不能像別人視頻中那樣流暢準確的進行解碼,基本上輸出的結果沒幾個是對的上的,因此此路行不通,開始萌生了放棄的想法,後來發現可以直接調取微信的掃碼功能,來實現我們的需求,因此開始了微信 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
接口安全域名
這樣我們的問題就能迎刃而解,在配置安全域名的時候,注意訪問的域名不要啓動代理,不然會綁定不成功
至此我們的需求得以完成,文章可能看起來很容易,但是實際操作起來會用很多各種各樣的問題,希望這篇文章能夠幫助到有類似需求的你
小 tips:遇到問題的時候可以嘗試在微信交流平臺找答案,或者可以查看官方文檔
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/vWbbs4vdG8Uy4zoNH-pTaQ