文章目录
- vue-qrcode-reader
- html5-qrcode
- 介绍
- 使用
- 页面调用
vue-qrcode-reader
vue-qrcode-reader主要依赖Stream API
,不支持Vue Native
- 下载vue-qrcode-reader插件:
npm install vue-qrcode-reader
- 引入
QrcodeStream
调用摄像头扫码(还提供了拍照或选择相册扫码,看个人需求)- 调用
init
(初始化摄像机)和decode
(返回二维码编码的字符串)/detect
(在decode之前触发;还会返回相机框架内二维码的坐标)方法
注意:
- Chrome需要Https或本地主机环境
- 在Chrome浏览器中,不能第二次提示用户访问相机权限,一旦拒绝,只能手动授予权限
不支持:彩色反转二维码(深色背景、浅色前景)、Model 1 二维码。
<template>
<div style="height: 100%; width: 100%">
<MyHeader :name="'扫码'" left="arrow-left" @goBackEv="$emit('goBack')" />
<qrcode-stream
:key="_uid"
:track="this.paintBoundingBox"
@decode="onDecode"
@init="onInit"
/>
</div>
</template>
<script>
import { QrcodeStream } from 'vue-qrcode-reader'
export default {
components: { QrcodeStream },
methods: {
onDecode(result) {
console.log('扫码结果', result)
this.$emit('goBack', result)
},
async onInit(promise) {
try {
await promise
} catch (error) {
if (error.name === 'NotAllowedError') {
// ERROR: you need to grant camera access permission
this.$toast("您需要授予摄像机访问权限")
} else if (error.name === 'NotFoundError') {
// ERROR: no camera on this device
this.$toast("这个设备上没有摄像头")
} else if (error.name === 'NotSupportedError') {
// ERROR: secure context required (HTTPS, localhost)
this.$toast("需要安全上下文(HTTPS, localhost)")
} else if (error.name === 'NotReadableError') {
// ERROR: is the camera already in use?
this.$toast("摄像机已经在使用了吗?")
} else if (error.name === 'OverconstrainedError') {
// ERROR: installed cameras are not suitable
this.$toast("安装的摄像头不合适")
} else if (error.name === 'StreamApiNotSupportedError') {
// ERROR: Stream API is not supported in this browser
this.$toast("此浏览器不支持流API")
} else if (error.name === 'InsecureContextError') {
// ERROR: Camera access is only permitted in secure context.
// Use HTTPS or localhost rather than HTTP.
this.$toast(`摄像头只能在安全环境下使用。使用HTTPS或本地主机,而不是HTTP`)
} else {
this.$toast(`ERROR: Camera error (${error.name})`)
}
}
},
/** 追踪二维码的样式
* 注意: 避免访问这个函数中的变量、计算属性以及vuex,该函数是每秒调用,会造成内存泄漏
* detectedCodes:位置对象
* ctx:CanvasRenderingContext2D实例
*/
paintBoundingBox(detectedCodes, ctx) {
for (const detectedCode of detectedCodes) {
const { boundingBox: { x, y, width, height } } = detectedCode
ctx.lineWidth = 2
ctx.strokeStyle = '#007bff'
ctx.strokeRect(x, y, width, height)
}
}
}
}
</script>
<style>
</style>
效果
html5-qrcode
介绍
html5-qrcode是轻量级和跨平台的QR码和条形码扫码的JS库,集成二维码、条形码和其他一些类型的代码扫描功能,代码依赖于Zxing-js
库
优势:
- 支持扫描不同类型的条形码和二维码
- 支持不同平台,Android、IOS、MacOS、Windows或Linux
- 支持不同的浏览器,如Chrome、Firefox、Safari、Edge
- 支持相机扫描以及本地文件
- 附带一个端到端库与UI以及一个低级库,以建立自己的UI
- 支持自定义,如闪光/火炬支持、缩放等
使用
- 下载html5-qrcode插件:
npm install html5-qrcode
- 添加一个元素,作为一个占位符的二维码扫描仪(高度由摄像机的视频馈送的纵横比得出)
<div id="reader" width="375px"></div>
注意:直接访问摄像头,涉及到隐私,所以环境必须是
https
<template>
<div style="height: 100%; width: 100%">
<MyHeader :name="'调用摄像头扫码'" left="arrow-left" @goBackEv="$emit('goBack')" />
<div class="qrcode">
<div id="reader"></div>
</div>
</div>
</template>
<script>
import { Html5Qrcode } from "html5-qrcode"
export default {
components: { QrcodeStream },
data() {
return {
html5QrCode: null
}
},
created() {
this.getCameras()
},
beforeDestroy() {
if (this.html5QrCode) this.stop()
},
methods: {
getCameras() {
Html5Qrcode.getCameras()
.then((devices) => {
if (devices && devices.length) {
this.html5QrCode = new Html5Qrcode("reader")
this.start()
}
})
.catch((err) => {
// handle err
this.html5QrCode = new Html5Qrcode("reader")
this.$toast('您需要授予相机访问权限')
})
},
start() {
this.html5QrCode
.start(
// environment后置摄像头 user前置摄像头
{ facingMode: "environment" },
{
fps: 2, // 可选,每秒帧扫描二维码
qrbox: { width: 250, height: 250 }, // 可选,如果你想要有界框UI
// aspectRatio: 1.777778 // 可选,视频馈送需要的纵横比,(4:3--1.333334, 16:9--1.777778, 1:1--1.0)传递错误的纵横比会导致视频不显示
},
(decodedText, decodedResult) => {
// do something when code is read
console.log('decodedText', decodedText);
console.log('decodedResult', decodedResult);
this.$emit("goBack", decodedText)
}
)
.catch((err) => {
console.log('扫码错误信息', err);
// 错误信息处理仅供参考,具体情况看输出!!!
if (typeof err == 'string') {
this.$toast(err)
} else {
if (err.name == 'NotAllowedError') return this.$toast("您需要授予相机访问权限")
if (err.name == 'NotFoundError') return this.$toast('这个设备上没有摄像头')
if (err.name == 'NotSupportedError') return this.$toast('摄像头访问只支持在安全的上下文中,如https或localhost')
if (err.name == 'NotReadableError') return this.$toast('相机被占用')
if (err.name == 'OverconstrainedError') return this.$toast('安装摄像头不合适')
if (err.name == 'StreamApiNotSupportedError') return this.$toast('此浏览器不支持流API')
}
})
},
stop() {
this.html5QrCode.stop().then((ignore) => {
// QR Code scanning is stopped.
console.log("QR Code scanning stopped.")
})
.catch((err) => {
// Stop failed, handle it.
console.log("Unable to stop scanning.")
})
},
}
}
</script>
<style lang="less" scoped>
.qrcode {
position: relative;
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, 0.1);
}
#reader {
top: 20%;
left: 0;
}
</style>
效果
页面调用
<template>
<div>
<div v-if="isStart ">
<!-- 页面其他结构 -->
</div>
<ScanView
v-else
@goBack="getScanResult"
/>
</div>
</template>
<script>
import ScanView from '@/components/scanView/index.vue'
export default {
data() {
return {
isStart : false
}
},
components: { ScanView },
methods: {
getScanResult(result) {
console.log('接收扫码结果', result)
if (result) {
// 处理逻辑
}
this.isStart = false
},
}
}
</script>