celsius的个人博客

星星之火可以燎原

0%

uniapp,vue3,h5端使用zxing扫描二维码,条形码


前言

废话不多说,使用uniapp时scan方法不支持h5端,因此h5端需要自己引入三方库,我这里用的是zxing
完整代码在最后


一、引入zxing

这里有两种方法,npm和直接使用js文件,按需使用

npm

1
pnpm add @zxing/library
1
import { BrowserMultiFormatReader } from '@zxing/library'

直接使用js文件

js地址:https://unpkg.com/@zxing/library@latest/umd/index.min.js

1
import { BrowserMultiFormatReader } from '@/utils/zxing.js'

二、功能实现

直接使用zxing提供的方法就行,默认参数就够用,如果需要自定义,比如修改视频流清晰度之类的可以看看文档

1. 获取摄像头

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 这里的处理是因为uniapp会对video标签进行二次封装
var video = document.getElementById('video_nav_id').getElementsByTagName('video')[0]
video.setAttribute('id', 'video_id')
video.setAttribute('class', 'video_calss')
codeReader.value = new BrowserMultiFormatReader();
codeReader.value.listVideoInputDevices().then(res => {
if (res.length > 0) {
videoInputDevices.value = res
// 这里默认选择最后一个摄像头
deviceId.value = res[res.length - 1].deviceId
} else {
// 没有可用的摄像头
// todo
}
}).catch(err => {
console.error(err)
})

2.开始扫描

1
2
3
4
5
6
7
try {
codeReader.value.decodeFromVideoDevice(deviceId.value, 'video_id', (res, err) => {
if (res) handleScanningResult(res)
})
} catch (err) {
uni.showToast({ title: `初始化失败${err}`, icon: 'none' });
}

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
<template>
<view class="camera_page">
<view class="camera_content">
<view class="code_close" @click="closeClick()">
<!-- <img src="../../static/close.png"> -->
</view>
<view class="loop_line"></view>
<view class="video_nav">
<video id="video_nav_id" autoplay :controls="false"></video>
</view>
</view>
</view>
</template>
<script setup>
import { onLoad } from "@dcloudio/uni-app";
import { ref } from "vue";
import { BrowserMultiFormatReader } from '@zxing/library'
// import { BrowserMultiFormatReader } from '@/utils/zxing.js'
const codeReader = ref(null)
const deviceId = ref(null)
const videoInputDevices = ref([])
const initEvent = () => {
// 这里的处理是因为uniapp会对video标签进行二次封装
var video = document.getElementById('video_nav_id').getElementsByTagName('video')[0]
video.setAttribute('id', 'video_id')
video.setAttribute('class', 'video_calss')
codeReader.value = new BrowserMultiFormatReader();
codeReader.value.listVideoInputDevices().then(res => {
if (res.length > 0) {
videoInputDevices.value = res
// 这里默认选择最后一个摄像头
deviceId.value = res[res.length - 1].deviceId
} else {
// 没有可用的摄像头
// todo
}
}).catch(err => {
console.error(err)
})
startScanning()
}
onLoad(() => {
setTimeout(() => {
initEvent();
}, 3000);
});
const startScanning = () => {
try {
codeReader.value.decodeFromVideoDevice(deviceId.value, 'video_id', (res, err) => {
if (res) handleScanningResult(res)
})
} catch (err) {
uni.showToast({ title: `初始化失败${err}`, icon: 'none' });
}
}
let startTime = null
const handleScanningResult = (res) => {
if (!startTime) startTime = new Date().getTime()
// 间隔时间500ms
const time = 500
if (new Date().getTime() - startTime >= time) {
startTime = null
// 这里处理扫描结果
console.log(res.text)
}
}
// 停止扫描
const stopScanning = () => {
codeReader.value.reset()
}
const closeClick = () => {
// todo
}
</script>
<style scoped lang="scss">
.camera_page {
height: 100vh;
width: 100vw;
}

.camera_content {
height: 100%;
width: 100%;
position: relative;
}

.code_close {
height: 50rpx;
width: 50rpx;
position: absolute;
left: 30rpx;
top: 30rpx;
z-index: 999999;
}

.code_close>img {
height: 100%;
width: 100%;
display: block;
}

.loop_line {
height: 3px;
width: 80%;
background-color: aliceblue;
border-radius: 50%;
box-shadow: 1px -4px 25px 7px rgba(255, 255, 255, 0.5);
position: absolute;
left: 50%;
top: 20%;
transform: translateX(-50%);
animation: myfirst 3s infinite;
z-index: 999999;
}

@keyframes myfirst {
from {
top: 20%;
}

to {
top: 80%;
}
}

.video_nav {
height: 100%;
width: 100%;
}

#video_nav_id {
height: 100%;
width: 100%;
}

:deep(.uni-video-cover) {
display: none;
}
</style>

注意事项:
摄像头权限需要https协议才能调用,也即

  1. 部署到服务器时,域名需要SSL证书,也就是域名以https开头
  2. 本地开发调试时,需要开启https并加载本地证书,这里可以看看我的另一篇笔记vue项目,uniapp项目开启https,加载本地证书