前言
废话不多说,使用uniapp时scan方法不支持h5端,因此h5端需要自己引入三方库,我这里用的是zxing
完整代码在最后
一、引入zxing
这里有两种方法,npm和直接使用js文件,按需使用
npm
pnpm add @zxing/library
import { BrowserMultiFormatReader } from '@zxing/library'
直接使用js文件
js地址:https://unpkg.com/@zxing/library@latest/umd/index.min.js
import { BrowserMultiFormatReader } from '@/utils/zxing.js'
二、功能实现
直接使用zxing提供的方法就行,默认参数就够用,如果需要自定义,比如修改视频流清晰度之类的可以看看文档
1. 获取摄像头
// 这里的处理是因为uniapp会对video标签进行二次封装,vue的话直接用ref获取dom就行
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.开始扫描
try {
codeReader.value.decodeFromVideoDevice(deviceId.value, 'video_id', (res, err) => {
if (res) handleScanningResult(res)
})
} catch (err) {
uni.showToast({ title: `初始化失败${err}`, icon: 'none' });
}
完整代码
<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' //npm引入
// import { BrowserMultiFormatReader } from '@/utils/zxing.js' //直接引入js文件
const codeReader = ref(null)
const deviceId = ref(null)
const videoInputDevices = ref([])
const initEvent = () => {
// 这里的处理是因为uniapp会对video标签进行二次封装,如果是Vue的话直接获取video标签
var video = document.getElementById('video_nav_id').getElementsByTagName('video')[0] // uniapp
// var video = document.getElementById('video_nav_id') //Vue
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' });
}
}
const handleScanningResult = (res) => {
// 这里处理扫描结果
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协议才能调用,也即
- 部署到服务器时,域名需要SSL证书,也就是域名以https开头
- 本地开发调试时,需要开启https并加载本地证书,这里可以看看我的另一篇笔记vue项目,uniapp项目开启https,加载本地证书