Vue實現長按圖片識別圖中二維碼
思路:要想實現可以識別圖片中的二維碼,那必定是要將這張圖進行上傳操作,上傳則需要file對象格式。不管是在H5還是APP中,展示的圖片都是通過url的方式展示在img標簽中的,所以大致的思路就是長按圖片,獲取圖片url,並將url轉換成可實現上傳操作的file對象格式,再通過某個插件對上傳的file進行是否存在QR碼的識別判斷操作,從而實現了長按識別二維碼,思路成立,開始實現。
1. 首先我們需要實現長按某張圖片,幾百毫秒后執行下一步操作,這一步就包括了獲取這張圖片url,這一步可以通過@touchstart結合setTimeout實現。
// 標簽中
<div class="image-preview" @touchstart="holdDown"></div>
// js中
holdDown (e) {
setTimeout(() => {
// 這是通過長按獲取到了html標簽,下面這個if語句就是為了識別是否是img標簽,通過e.target.nodeName獲取
if(e.target.nodeName === 'IMG'){
// 這里可以做很多事,比如vant組件的動作面板,或是對話框等等,方便識別二維碼成功后的后續操作,例如點擊識別二維碼,這個是你自己定的。
this.showSheet = true
// 提前通過e.target.currentSrc獲取到圖片的src,也就是圖片的url地址,並把它存起來。
this.imgUrl = e.target.currentSrc
// 拿到url后,我們就需要將圖片的url地址轉化成file對象格式,也就是俗稱的文件格式。這里我們最好封裝一個方法,傳入url,通過返回值獲取到它的值。
this.urlToFile(url)
// 未完 繼續往下看
}
},500)
}
2. 我們需要封裝一個可以將url的圖片地址轉換成可上傳的file對象格式,這里就是整個實現代碼的核心。
urlToFile (url, callback) { // 建議封裝,全局使用
const image = new Image() // 初始化一個image圖像
image.crossOrigin = '*' // 這個是為了解決圖片的跨域問題,有些時候不生效,則需要后端配置
image.src = url
image.onload = function () { // 當然在圖片加載完成后去執行以下代碼
const canvas = document.createElement('canvas') // 將image圖像轉化成canvas圖像
canvas.width = image.width // canvas長寬與image保持一致
canvas.height = image.height
const ctx = canvas.getContext('2d')
ctx.drawImage(image, 0, 0, image.width, image.height)
const ext = image.src.substring(image.src.lastIndexOf('.') + 1).toLowerCase()
const dataURL = canvas.toDataURL('image/' + ext) // 如果你的圖片格式是固定的,如jpg、png,則可以直接替換這里的ext,直接寫成例如image/png。
const type = 'image/' + ext
const bytes = window.atob(dataURL.split(',')[1]) // 去掉url的頭,並轉換為byte
const ab = new ArrayBuffer(bytes.length) //初始化一個bytes的二進制數組ArrayBuffer
const ia = new Uint8Array(ab) // 初始化,ab轉為Uint8Array數組類型
for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i)
}
const tempBlob = new Blob([ia], { type: type }) // 關鍵,初始化一個blob對象,blob支持文件操作
const blob = tempBlob
var file = new File([blob], 'filename', { type: type, lastModified: Date.now() })// 通過blob創建一個file文件
callback(file) // 為何用callback 而不是return?因為上面的onload中是閉包,我們無法直接return這個file
}
}
3. 還記得之前傳入url的那個方法嗎?我們回到長按方法holdDown方法中,再獲取callback的file值。
holdDown (e) {
setTimeout(() => {
.
. // 省略部分代碼
.
this.urlToFile(url, (file) => { // 通過箭頭函數拿到callback返回的值
console.log(file) //至此 你已經成功拿到url轉file的圖片文件,下一步就是上傳,並掃描二維碼
})
}
},500)
}
4. 市面上掃描圖片文件二維碼的插件並不多,甚至有大神手寫了一個reqrcode.js,但不適用於vue。這里我推薦qrcode-decoder插件,他可以通過傳入的file實現對圖片文件的掃描,識別是否存在二維碼,並獲取到二維碼的內容。
下載方式:
// npm 安裝
npm install qrcode-decoder
// 太慢了?淘寶鏡像安裝
npm install qrcode-decoder --registry=https://registry.npm.taobao.org
5. qrcode-decoder的使用方法
import QrCode from 'qrcode-decoder'
// 引入后,創建一個方法,用於識別圖片二維碼,當然你可以將這個方法封裝起來,全局注冊,便於使用。
identifyQR (file) {
// 獲取臨時路徑 chrome有效,其他瀏覽器的方法請自行查找
const url = window.webkitURL.createObjectURL(file)
console.log(url)
// 初始化
const qr = new QrCode()
// 解析二維碼,返回promise
return qr.decodeFromImage(url) //注意 這里返回的是一個promise對象
}
6. 再回到我們獲取到file處,使用這個方法,並進行后續操作
holdDown (e) {
setTimeout(() => {
.
. // 省略部分代碼
.
this.urlToFile(url, (file) => { // 通過箭頭函數拿到callback返回的值
this.identifyQR(file).then(r => { // 返回值為promise對象,所以通過.then獲取
if(r.data){// 其中寫你的操作,若有值,則說明是存在二維碼的,可以先存起來獲取到的二維碼的值,便於其他地方操作及使用
...
}else{
console.log('不是二維碼')
}
})
})
}
},500)
}
至此,成功實現了長按識別二維碼
總結:方法是自己摸索的,明明可以app解決的問題非要交給前端,不過解決思路還是很清晰的,如果有更好的方法,不妨交流交流。
感謝閱讀~