<template>
<form>
<div class="form-group">
<label>选择摄像头</label>
<select class="form-control" v-model="currentDevices">
<template v-if="videoInputDevices.length > 0">
<option v-for="item, index in videoInputDevices" :key="index" :value="item.value">{{ item.label }}</option>
</template>
</select>
</div>
<div class="form-group">
<label>扫描结果</label>
<input v-model="codeStr" type="text" class="form-control">
</div>
<button type="button" class="btn btn-primary" @click="scanStart" >打开扫描</button>
</form>
<!-- Modal -->
<div class="modal fade" id="scanModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">扫描二维码</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<!-- 扫描框 -->
<video id="video" width="400" height="200">
{{ currentDevices.label }}
</video>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" @click="scanCancel">关闭</button>
</div>
</div>
</div>
</div>
</template>
<script >
import { defineComponent, ref, onBeforeMount, onBeforeUnmount } from "vue";
import { BrowserMultiFormatReader } from '@zxing/library'
import { swal2 } from "./common";
export default defineComponent({
name: "ScanVue",
setup(){
const codeStr = ref('')
const codeReader = new BrowserMultiFormatReader()
// 所有视频输入设备
const videoInputDevices = ref([])
// 当前输入设备
const currentDevices = ref(null)
// 查找摄像头
async function deviceDetect(){
await codeReader.listVideoInputDevices().then((devices) => {
if(devices.length > 0){
videoInputDevices.value = []
// 摄像头倒叙:后置摄像头优先,默认顺序:前置,后置
devices.reverse()
swal2.success("摄像头检测成功")
videoInputDevices.value.push({label:'后置摄像头',value:devices[0]})
if(devices.length > 1){
videoInputDevices.value.push({label:'前置摄像头',value:devices[1]})
}
// 默认选择后置
currentDevices.value = devices[0]
}
})
.catch((err) => {swal2.error(`${err}`)})
}
/**
* 扫描回调函数
* @param {any} data 扫描结果,没有结果为null
*/
function decodeCallback(data){
if(data != null){ codeStr.value = data;scanCancel()}
}
// 解码
function decodeFromInputVideo(){
// 重置摄像头
codeReader.reset()
// currentDevices.value.deviceId 当前设备ID
// deviceId: string, videoSource: string | HTMLVideoElement
// let cam = videoInputDevices.value[0]
codeReader.decodeFromVideoDevice(currentDevices.value.deviceId, "video", decodeCallback).then((value, err) => {
// 结果字符串
if(value != undefined){
// 解码成功后关闭摄像头
codeReader.reset()
}
if(err){ swal2.error(`${err}`)}
})
.catch((err) => {swal2.error(`${err}`)})
}
function scanStart(){
$('#scanModal').modal('toggle')
decodeFromInputVideo()
}
function scanCancel(){
codeReader.reset()
$('#scanModal').modal('toggle')
}
onBeforeMount(() =>{
deviceDetect()
})
onBeforeUnmount(() =>{
codeReader.reset()
})
return {
videoInputDevices, scanStart, scanCancel, codeStr, currentDevices
}
}
})
</script>
<style scoped>
</style>
edge 浏览器启用: Allow invalid certificates for resources loaded from localhost. Insecure origins treated as secure
vue.config.js
devServer:{
host:'0.0.0.0',
port: 4000,
allowedHosts: ['.host.cn', 'host.cn'],
}