<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'],
}