如何在H5页面中添加二维码扫描功能?Uniapp如何支持H5的扫码功能呢?
最编程
2024-02-22 07:48:36
...
本文主要使用
html5-qrcode
库实现二维码扫描功能,官方github地址:github.com/mebjas/html…
引入html5-qrcode:
npm i html5-qrcode
或者:
<script src="https://unpkg.com/html5-qrcode" type="text/javascript">
注意事项:
- 浏览器需要在
https
或者localhost
下才能调用相机,关于本地调试如何启用https参考# 如何在本地启用https服务? - 浏览器需要开启相机使用权限
基本使用
实例化html5-qrcode
<div id="reader"></div>
<script>
// reader是DOM的id
var html5QrCode = new Html5Qrcode("reader")
</script>
识别文件夹中的二维码图片
// 返回promise对象,imageFile,file对象,第二个参数:是否将图片显示到画布上
html5QrCode.scanFile(imageFile, true)
.then(qr => {
console.log(qr) // 二维码结果
})
.catch(err => {
console.log(err)
})
扫码,利用相机进行扫码
// 获取相机设备
Html5Qrcode.getCameras()
.then(devices => {
// 扫码配置
const config = {
fps: 10, // 二维码扫描每秒帧数
qrbox: { width: 300, height: 300 }, // UI框的大小
aspectRatio: 1.777778, // 纵横比,此值表示全屏
}
if (devices && devices.length) {
const cameraId = devices[devices.length - 1].id //后置摄像头,一般最后一个是后置摄像头
//let cameraId = devices[0].id //前置摄像头
// 打开相机,开始扫描,callbackSuccess, callbackFailure扫描成功与失败的回调函数(自行定义)
html5QrCode.start({ deviceId: { exact: cameraId } }, config, callbackSuccess, callbackFailure).catch(err => {
alert(err)
})
} else {
// 如果没有找到设备,直接启用摄像头
//environment:后置摄像头 user:前置摄像头
html5QrCode.start({ facingMode: "environment" }, config, onScanSuccess, onScanFailure).catch(err => {
alert(err)
})
}
})
.catch(err => {
alert(err)
})
停止扫描
html5QrCode.stop()
清除画布
html5QrCode.clear()
vue中开发扫码页面
本次demo使用的是vue3,参考大多数扫码功能,都是以页面的形式展示,也可以封装为组件,主要看项目需求
思路:
- 点击扫描,跳转扫一扫页面,打开相机扫码
- 识别成功放回上一页,并将结果传递给上一页
实现效果:
主要实现代码:
demo源码:github.com/Abner105/sc…
ScanView.vue 扫码页面
- 主要实现调起相机扫码,并返回结果到上一个页面
<template>
<div>
<div @click="close" class="title">扫码 X</div>
<!-- 扫描仪占位符 -->
<div id="reader"></div>
</div>
</template>
<script setup>
import { Html5Qrcode } from "html5-qrcode"
import { onMounted } from "vue"
import { useRouter } from "vue-router"
import { onBeforeRouteLeave } from "vue-router"
const router = useRouter()
let html5QrCode = null
const scanRes = {} // 存放扫码结果
// 路由导航,将扫码结果放回给上一页
onBeforeRouteLeave(to => {
to.query.scanRes = scanRes
})
// 关闭扫码页面
const close = () => {
html5QrCode.stop().finally(() => {
html5QrCode.clear()
router.back()
})
}
// // 扫码成功的回调
const onScanSuccess = qr => {
scanRes.qr = qr
close()
}
// 使用相机扫码
const useCamera = () => {
// 实例化,接收元素id作为参数
html5QrCode = new Html5Qrcode("reader")
// 获取相机设备
Html5Qrcode.getCameras()
.then(devices => {
// 扫码配置
const config = {
fps: 10, // 二维码扫描每秒帧数
qrbox: { width: 300, height: 300 }, // UI框的大小
aspectRatio: 1.777778,
showTorchButtonIfSupported: true,
}
if (devices && devices.length) {
let cameraId = devices[devices.length - 1].id //后置摄像头,一般最后一个是后置摄像头
//let cameraId = devices[0].id //前置摄像头
html5QrCode.start({ deviceId: { exact: cameraId } }, config, onScanSuccess).catch(err => {
scanRes.err = err
router.back()
})
} else {
// 如果没有找到设备,直接启用摄像头
//environment:后置摄像头 user:前置摄像头
html5QrCode.start({ facingMode: "environment" }, config, onScanSuccess).catch(err => {
scanRes.err = err
router.back()
})
}
})
.catch(err => {
scanRes.err = err
router.back()
})
}
onMounted(() => {
useCamera()
})
</script>
HomeView.vue
- 调起扫码页面,处理扫码结果
- 选择二维码图片并识别二维码
<template>
<div>
<div class="title">Home</div>
<button class="button">
<input ref="inputRef" @change="useLocal" type="file" class="upload-input" accept="image/*" />
<span>选择二维码</span>
<div id="reader1"></div>
</button>
<button class="button" @click="useCamera">扫描二维码</button>
</div>
</template>
<script setup>
import { onMounted } from "vue"
import { Html5Qrcode } from "html5-qrcode"
import { useRouter } from "vue-router"
import { useRoute } from "vue-router"
const router = useRouter()
const route = useRoute()
onMounted(() => {
// 页面返回时,拿到扫码结果并处理
const { qr, err } = route.query.scanRes || {}
if (qr) {
alert(qr) // 处理扫码成功结果
} else if (err) {
alert(err) // 处理失败结果
}
})
// 选取二维码图片并识别
const useLocal = e => {
if (e.target.files.length == 0) {
return
}
const imageFile = e.target.files[0]
const html5QrCode = new Html5Qrcode("reader1")
html5QrCode.scanFile(imageFile, false)
.then(qr => {
alert(qr)
})
.catch(err => {
alert(err)
})
}
const useCamera = () => {
router.push("/scan") // 去扫码页面
}
</script>
<style>
.title{
height: 50px;
line-height: 50px;
}
button{
height: 50px;
width: 120px;
}
</style>
uniapp中封装扫码页面
uniapp中uni.scanCode()可以调起扫码功能,但该API不兼容H5,因此H5页面还是需要自己写一个扫码页面。整体逻辑还是参考vueH5页面的实现。
实现效果:
demo代码:
当前uniapp项目中二维码图片识别功能使用的是reqrcode.js库,也可以使用html5-qrcode,这里我懒得改了。
pagexxx.vue 扫一扫入口页面
<image src="/static/icon/scan.svg" @click="scancode"></image>
<script>
// #ifdef H5
const qrcode = require("@/utils/reqrcode.js") // 用于识别二维码图片
// #endif
export default {
data() {
return {
// #ifdef H5
scanResult: {}, // 扫码结果
// #endif
}
},
onShow() {
// #ifdef H5
if (this.scanResult.qr) {
this.handleScan(this.scanResult.qr)
} else if (this.scanResult.err) {
uni.showToast({
title: this.scanResult.err,
duration: 2000,
icon: "none",
})
}
this.scanResult = {}
// #endif
},
methods: {
handleScan(address) {
// 处理扫码逻辑
},
// 扫描二维码
scancode() {
let that = this
// #ifdef APP-PLUS
// APP使用uni自带的API
uni.scanCode({
scanType: ["qrCode"],
success: res => {
that.handleScan(res.result)
},
})
// #endif
// #ifdef H5
uni.showActionSheet({
itemList: ['扫描二维码', '选择二维码图片'],
success(res) {
if (!res.tapIndex) {
// 去扫码页面
uni.navigateTo({
url: "/pages/scan/scan",
})
} else {
// 选择二维码图片
uni.chooseImage({
count: 1,
success: function (res) {
const tempFilePaths = res.tempFilePaths
qrcode.decode(tempFilePaths[0])
qrcode.callback = function (img) {
if (img == "error decoding QR Code") {
uni.showToast({
title: "Incorrect QR code",
duration: 2000,
icon: "none",
})
} else {
that.handleScan(img)
}
}
},
})
}
},
})
// #endif
}
}
}
</script>
san.vue 扫一扫页面
<template>
<view>
<!-- uView的自定义导航栏,背景设置为透明 -->
<u-navbar
:title="$t('common.scan')"
@leftClick="closed"
:titleStyle="{ fontWeight: '600', color: '#ffffff' }"
bgColor="transparent"
leftIconColor="#ffffff"
></u-navbar>
<!-- 扫描仪占位符 -->
<view id="reader"></view>
</view>
</template>
<script>
import { Html5Qrcode } from "html5-qrcode"
export default {
data() {
return {
html5QrCode: null,
}
},
mounted() {
this.useCamera() // 打开相机
},
methods: {
// 关闭扫一扫页面,返回上一页
closed() {
this.html5QrCode.stop().finally(() => {
this.html5QrCode.clear()
uni.navigateBack()
})
},
scanRes(qr, err) {
// 修改上一个页面的数据,传递qr
var pages = getCurrentPages()
var prevPage = pages[pages.length - 2]
prevPage.$vm.scanResult = { qr, err }
},
// 成功回调
onScanSuccess(qr) {
this.scanRes(qr)
this.closed()
},
useCamera() {
// 实例化,接收元素id作为参数
this.html5QrCode = new Html5Qrcode("reader")
// 获取相机设备
Html5Qrcode.getCameras()
.then(devices => {
// 扫码配置
const config = {
fps: 10, // 二维码扫描每秒帧数
qrbox: {
width: 300,
height: 300,
}, // UI框的大小
aspectRatio: 1.777778,
}
if (devices && devices.length) {
let cameraId = devices[devices.length - 1].id //后置摄像头,一般最后一个是后置摄像头
//let cameraId = devices[0].id //前置摄像头
this.html5QrCode
.start({ deviceId: { exact: cameraId, }, }, config, this.onScanSuccess)
.catch(err => {
this.scanRes(undefined, err)
uni.navigateBack()
})
} else {
// 如果没有找到设备,直接启用摄像头
//environment:后置摄像头 user:前置摄像头
this.html5QrCode
.start( { facingMode: "environment" }, config, this.onScanSuccess )
.catch(err => {
this.scanRes(undefined, err)
uni.navigateBack()
})
}
})
.catch(err => {
this.scanRes(undefined, err)
uni.navigateBack()
})
},
},
}
</script>