Vue + zxing 实现扫二维码、条形码功能
zXing :一个开源的、多格式的一维/二维条码图像处理库; 地址: https://github.com/zxing-js/library
官方提供的多种扫描案例:https://zxing-js.github.io/library/
注意: Zxing 只能运行在 'localhost' 或者 ‘https’ 域名下(webRTC必须在https环境下运行);
使用 zxing 前提 :必须保证摄像头正常,我们可以打开相机测试相机是否可用,如果可用请跳过直接看下面的实现代码;
如果在打开相机时,发现提示"找不到你的相机",打开 设备管理器 也找不到 照相机 ,可参考下面的解决办法;
解决办法:直接 Fn+F6 键(不同的电脑按键可能不一样,记得找摄像头标识的按键),然后稍等一会发现 设备管理器 出现了 照相机 !!
安装插件
npm install @zxing/library
npm install --save webrtc-adapter
案例一、
<template>
<div class="page-scan">
<!-- 扫码区域 -->
<div class="QrCode">
<video ref="video" height="100%" width="100%" id="video" autoplay></video>
</div>
<!-- 扫码样式一 -->
<div class="Qr_scanner">
<div class="box">
<div class="line_row">
<div class="line"></div>
</div>
<div class="angle"></div>
</div>
</div>
</div>
</template>
<script>
// WebRTC适配器 只需要引入就ok
import 'webrtc-adapter'
import { BrowserMultiFormatReader } from '@zxing/library'
export default {
name: 'scanCodePage',
data() {
return {
codeReader: null
}
},
mounted() {
this.codeReader = new BrowserMultiFormatReader()
this.openScan()
},
beforeUnmount() {
this.codeReader && this.codeReader.reset()
},
methods: {
async openScan() {
this.codeReader
.listVideoInputDevices()
.then((videoInputDevices) => {
// 默认获取第一个摄像头设备id
let firstDeviceId = videoInputDevices[0].deviceId
// 获取第一个摄像头设备的名称
const videoInputDeviceslablestr = JSON.stringify(
videoInputDevices[0].label
)
if (videoInputDevices.length > 1) {
// 判断是否后置摄像头
if (videoInputDeviceslablestr.indexOf('back') > -1) {
firstDeviceId = videoInputDevices[0].deviceId
} else {
firstDeviceId = videoInputDevices[1].deviceId
}
}
this.codeReader && this.codeReader.reset() // 重置
this.decodeFromInputVideoFunc(firstDeviceId)
})
.catch((err) => {
console.error(err)
})
},
decodeFromInputVideoFunc(firstDeviceId) {
this.codeReader.decodeFromInputVideoDeviceContinuously(
firstDeviceId,
'video',
(result, err) => {
if (result) {
console.log('扫描结果', result)
// if (result.text) {
// this.clickIndexLeft(result.text)
// }
}
if (err && !err) {
console.error(err)
}
}
)
},
// 停止扫描,并返回上一页
clickIndexLeft(result) {
this.codeReader && this.codeReader.reset()
this.codeReader = null
// this.$route.params.result = result
// this.$router.back()
}
}
}
</script>
<style lang="scss" scope>
.QrCode {
width: 100vw;
height: 100vh;
position: relative;
#video {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.Qr_scanner {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
}
.Qr_scanner .box {
width: 75vw;
height: 75vw;
max-height: 75vh;
max-width: 75vh;
position: relative;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border: 1px solid rgb(43, 113, 254);
.line_row {
width: 100%;
overflow: hidden;
background-image: linear-gradient(
0deg,
transparent 24%,
rgba(136, 176, 255, 0.1) 25%,
rgba(136, 176, 255, 0.1) 26%,
transparent 27%,
transparent 74%,
rgba(136, 176, 255, 0.1) 75%,
rgba(136, 176, 255, 0.1) 76%,
transparent 77%,
transparent
),
linear-gradient(
90deg,
transparent 24%,
rgba(136, 176, 255, 0.1) 25%,
rgba(136, 176, 255, 0.1) 26%,
transparent 27%,
transparent 74%,
rgba(136, 176, 255, 0.1) 75%,
rgba(136, 176, 255, 0.1) 76%,
transparent 77%,
transparent
);
background-size: 3rem 3rem;
background-position: -1rem -1rem;
animation: Heightchange 2s infinite;
animation-timing-function: cubic-bezier(0.53, 0, 0.43, 0.99);
animation-delay: 1.4s;
border-bottom: 1px solid rgba(136, 176, 255, 0.1);
display: flex;
justify-content: center;
align-items: flex-end;
}
}
.Qr_scanner .line {
width: 100%;
height: 3px;
background: #2b71fe;
// opacity: 0.58;
filter: blur(4px);
}
.Qr_scanner .box:after,
.Qr_scanner .box:before,
.Qr_scanner .angle:after,
.Qr_scanner .angle:before {
content: '';
display: block;
position: absolute;
width: 78px;
height: 78px;
border: 0.3rem solid transparent;
}
.Qr_scanner .box:after,
.Qr_scanner .box:before {
top: -7px;
border-top-color: #2b71fe;
}
.Qr_scanner .angle:after,
.Qr_scanner .angle:before {
bottom: -7px;
border-bottom-color: #2b71fe;
}
.Qr_scanner .box:before,
.Qr_scanner .angle:before {
left: -7px;
border-left-color: #2b71fe;
}
.Qr_scanner .box:after,
.Qr_scanner .angle:after {
right: -7px;
border-right-color: #2b71fe;
}
@keyframes radar-beam {
0% {
transform: translateY(-100%);
}
100% {
transform: translateY(0);
}
}
@keyframes Heightchange {
0% {
height: 0;
}
100% {
height: 100%;
}
}
</style>
案例二、
<template>
<div class="page-scan">
<!-- 扫码区域 -->
<div class="QrCode">
<video ref="video" height="100%" width="100%" id="video" autoplay></video>
</div>
<!-- 扫码样式 -->
<div class="qr-scanner">
<div class="box">
<div class="line"></div>
<div class="angle"></div>
</div>
<div class="back-arrow" @click="clickIndexLeft">
<span>返回</span>
</div>
</div>
</div>
</template>
<script>
// WebRTC适配器 只需要引入就ok
import 'webrtc-adapter'
import { BrowserMultiFormatReader } from '@zxing/library'
export default {
name: 'scanCodePage',
data() {
return {
codeReader: null
}
},
mounted() {
this.codeReader = new BrowserMultiFormatReader()
this.openScan()
},
beforeUnmount() {
this.codeReader && this.codeReader.reset()
},
methods: {
async openScan() {
this.codeReader
.listVideoInputDevices()
.then((videoInputDevices) => {
// 默认获取第一个摄像头设备id
let firstDeviceId = videoInputDevices[0].deviceId
// 获取第一个摄像头设备的名称
const videoInputDeviceslablestr = JSON.stringify(
videoInputDevices[0].label
)
if (videoInputDevices.length > 1) {
// 判断是否后置摄像头
if (videoInputDeviceslablestr.indexOf('back') > -1) {
firstDeviceId = videoInputDevices[0].deviceId
} else {
firstDeviceId = videoInputDevices[1].deviceId
}
}
this.codeReader && this.codeReader.reset() // 重置
this.decodeFromInputVideoFunc(firstDeviceId)
})
.catch((err) => {
console.error(err)
})
},
decodeFromInputVideoFunc(firstDeviceId) {
this.codeReader.decodeFromInputVideoDeviceContinuously(
firstDeviceId,
'video',
(result, err) => {
if (result) {
console.log('扫描结果', result)
// if (result.text) {
// this.clickIndexLeft(result.text)
// }
}
if (err && !err) {
console.error(err)
}
}
)
},
// 停止扫描,并返回上一页
clickIndexLeft(result) {
this.codeReader && this.codeReader.reset()
this.codeReader = null
// this.$route.params.result = result
// this.$router.back()
}
}
}
</script>
<style lang="scss" scope>
.qr-scanner {
background-image: linear-gradient(
0deg,
transparent 24%,
rgba(32, 255, 77, 0.1) 25%,
rgba(32, 255, 77, 0.1) 26%,
transparent 27%,
transparent 74%,
rgba(32, 255, 77, 0.1) 75%,
rgba(32, 255, 77, 0.1) 76%,
transparent 77%,
transparent
),
linear-gradient(
90deg,
transparent 24%,
rgba(32, 255, 77, 0.1) 25%,
rgba(32, 255, 77, 0.1) 26%,
transparent 27%,
transparent 74%,
rgba(32, 255, 77, 0.1) 75%,
rgba(32, 255, 77, 0.1) 76%,
transparent 77%,
transparent
);
background-size: 3rem 3rem;
background-position: -1rem -1rem;
// width: 100%;
// height: 100%;
// position: relative;
// background-color: #111;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
}
.qr-scanner .box {
width: 75vw;
height: 75vw;
max-height: 75vh;
max-width: 75vh;
position: relative;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
overflow: hidden;
border: 0.1rem solid rgba(0, 255, 51, 0.2);
}
.qr-scanner .line {
height: calc(100% - 2px);
width: 100%;
background: linear-gradient(180deg, rgba(0, 255, 51, 0) 43%, #00ff33 211%);
border-bottom: 3px solid #00ff33;
transform: translateY(-100%);
animation: radar-beam 2s infinite;
animation-timing-function: cubic-bezier(0.53, 0, 0.43, 0.99);
animation-delay: 1.4s;
}
.qr-scanner .box:after,
.qr-scanner .box:before,
.qr-scanner .angle:after,
.qr-scanner .angle:before {
content: '';
display: block;
position: absolute;
width: 3vw;
height: 3vw;
border: 0.2rem solid transparent;
}
.qr-scanner .box:after,
.qr-scanner .box:before {
top: 0;
border-top-color: #00ff33;
}
.qr-scanner .angle:after,
.qr-scanner .angle:before {
bottom: 0;
border-bottom-color: #00ff33;
}
.qr-scanner .box:before,
.qr-scanner .angle:before {
left: 0;
border-left-color: #00ff33;
}
.qr-scanner .box:after,
.qr-scanner .angle:after {
right: 0;
border-right-color: #00ff33;
}
@keyframes radar-beam {
0% {
transform: translateY(-100%);
}
100% {
transform: translateY(0);
}
}
.qr-scanner .back-arrow {
position: fixed;
top: 20px;
left: 20px;
width: 30px;
height: 30px;
border-radius: 100%;
background-color: rgba(0, 0, 0, 0.3);
z-index: 999;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
}
</style>
想测试的大家可以借助 ‘草料二维码’ 生成二维码测试;
参考文章
https://www.cnblogs.com/memphis-f/p/15543115.html
https://blog.csdn.net/qq_41120902/article/details/116176714