Vue3使用vue-qrcode-reader實(shí)現(xiàn)掃碼綁定設(shè)備功能(推薦)
需求描述
移動(dòng)端進(jìn)入網(wǎng)站后,登錄網(wǎng)站進(jìn)入設(shè)備管理界面。點(diǎn)擊添加設(shè)備,可以選擇直接添加或者掃一掃。點(diǎn)擊掃一掃進(jìn)行掃描二維碼獲取設(shè)備序列號(hào)自動(dòng)填充到添加設(shè)備界面的序列號(hào)輸入框中。然后點(diǎn)擊完成進(jìn)行設(shè)備綁定。
安裝vue-qrcode-reader 這里使用的版本是5.5.7
npm install vue-qrcode-reader --save
掃一掃界面ScanCode.vue
<template>
<div class="block-main">
<div class="head-wrap">
<img
src="../../assets/images/mobile/icon-arrow-left.png"
class="btn-back"
@click="goback"
/>
<span class="title">掃一掃</span>
</div>
<div class="qr-container">
<qrcode-stream
@detect="onDecode"
@camera-on="onCameraReady"
@error="onError"
/>
</div>
</div>
</template>
<script>
import { reactive, ref, onMounted } from "vue";
import { useRouter } from "vue-router";
import { QrcodeStream } from "vue-qrcode-reader";
import { showToast } from "vant";
export default {
components: {
QrcodeStream,
showToast,
},
setup() {
const testVice = reactive([]);
const router = useRouter();
// 掃碼成功后的回調(diào)
const onDecode = (detectedCodes) => {
if (detectedCodes.length > 0) {
// 跳轉(zhuǎn)到添加設(shè)備頁(yè)面并傳遞設(shè)備編號(hào)
let deviceCode = detectedCodes[0].rawValue;
router.replace({
path: "/deviceadd",
query: { deviceCode },
});
} else {
showToast("掃碼失敗");
}
};
const onCameraReady = (res) => {
console.log("攝像頭準(zhǔn)備好了");
};
const onError = (error) => {
if (error.name === "NotAllowedError") {
// user denied camera access permission
showToast("用戶拒絕相機(jī)訪問(wèn)權(quán)限");
} else if (error.name === "NotFoundError") {
// no suitable camera device installed
showToast("未安裝合適的攝像設(shè)備");
} else if (error.name === "NotSupportedError") {
// page is not served over HTTPS (or localhost)
showToast("當(dāng)前網(wǎng)頁(yè)沒(méi)有通過(guò) HTTPS 或 localhost 安全協(xié)議提供服務(wù)");
} else if (error.name === "NotReadableError") {
// maybe camera is already in use
showToast("相機(jī)被占用了)");
} else if (error.name === "OverconstrainedError") {
// did you request the front camera although there is none?
showToast("嘗試使用前置攝像頭)");
} else if (error.name === "StreamApiNotSupportedError") {
showToast("瀏覽器似乎缺少功能)");
// browser seems to be lacking features
}
};
onMounted(() => {
navigator.mediaDevices
.enumerateDevices()
.then((devices) => {
devices.forEach((device) => {
if (device.kind === "videoinput") {
console.log(
"Video input device: ",
device.label,
device.deviceId
);
}
});
})
.catch((error) => {
console.error("Error enumerating devices: ", error);
showToast("Error enumerating devices");
});
});
const goback = () => {
router.go(-1);
};
return {
testVice,
onCameraReady,
goback,
onDecode,
onError,
};
},
};
</script>
<style lang="scss" scoped>
.block-main {
height: 100%;
background: #fff;
overflow: hidden;
font-size: 16px;
.head-wrap {
height: 0.96rem;
background: #31be7c;
font-family: Microsoft YaHei UI;
font-weight: 400;
color: #fff;
display: flex;
align-items: center;
position: fixed;
left: 0;
right: 0;
.btn-back {
margin-left: 0.4rem;
width: 0.22rem;
height: 0.38rem;
}
.title {
font-size: 0.36rem;
text-align: center;
flex: 1;
}
}
.qr-container {
display: flex;
justify-content: center;
align-items: center;
height: calc(100vh - 0.96rem); // 減去頭部的高度
margin-top: 0.96rem;
}
}
</style>添加設(shè)備界面DeviceAdd.vue
<template>
<div class="block-main">
<div class="head-wrap">
<a href="javascript:void(0)" rel="external nofollow" rel="external nofollow" class="btn-cancel" @click="goBack">取消</a>
<span class="title"></span>
<a href="javascript:void(0)" rel="external nofollow" rel="external nofollow" class="btn-sure" @click="deviceReg">完成</a>
</div>
<div class="input-wrap" @click="showDeviceType">
<span class="input">{{ deviceInfo.devtypeName }}</span>
<img
src="../../assets/images/mobile/icon-arrow-right.png"
class="icon-arrow"
/>
</div>
<div class="input-wrap">
<input
type="text"
class="input"
v-model="deviceInfo.devsn"
placeholder="請(qǐng)輸入設(shè)備序列號(hào)"
/>
<img
v-if="deviceInfo.devsn"
src="../../assets/images/mobile/icon-close-gray.png"
class="icon-close"
@click="clearInput"
/>
</div>
<div class="error-msg">{{ deviceInfo.devsn_error }}</div>
<van-popup v-model:show="deviceTypeDialog" position="bottom">
<van-picker
:columns="devTypes"
v-model:value="deviceInfo.devtype"
@cancel="deviceTypeDialog = false"
@confirm="onConfirm"
/>
</van-popup>
</div>
</template>
<script>
import { ref, reactive, onMounted } from "vue";
import { useRoute,useRouter } from "vue-router";
import {
Picker,
Popup,
showFailToast,
showSuccessToast,
showToast,
showLoadingToast,
} from "vant";
import { device_Reg } from "../../api/auth";
export default {
components: {
"van-picker": Picker,
"van-popup": Popup,
},
setup() {
const route = useRoute();
const deviceTypeDialog = ref(false);
const router = useRouter();
const devTypes = [
{ value: 1, text: "設(shè)備類型1" },
{ value: 2, text: "設(shè)備類型2" },
{ value: 3, text: "設(shè)備類型3" },
];
const deviceInfo = reactive({
devtype: null,
devtypeName: "請(qǐng)選擇需要綁定的設(shè)備",
devsn: "",
devsn_error: "",
});
const showDeviceType = () => {
deviceTypeDialog.value = true;
};
const clearInput = () => {
deviceInfo.devsn = "";
deviceInfo.devsn_error = "";
};
const onConfirm = ({ selectedOptions }) => {
deviceTypeDialog.value = false;
deviceInfo.devtype = selectedOptions[0].value;
deviceInfo.devtypeName = selectedOptions[0].text;
};
const goBack = () => {
router.go(-1);
};
const deviceReg = async () => {
if (deviceInfo.devtype == null) {
deviceInfo.devsn_error = "請(qǐng)選擇設(shè)備類型";
return;
}
if (!deviceInfo.devsn) {
deviceInfo.devsn_error = "請(qǐng)?zhí)顚懺O(shè)備序列號(hào)";
return;
}
const toast = showLoadingToast({
message: "數(shù)據(jù)提交中...",
forbidClick: true,
});
let response = await device_Reg({
devsn: deviceInfo.devsn,
devtype: deviceInfo.devtype,
});
if (response.isSuccess == true) {
toast.close();
showSuccessToast("設(shè)備綁定成功");
setTimeout(() => {
router.go(-1);
}, 2000);
} else {
deviceInfo.devsn_error = response.message;
toast.close();
}
};
onMounted(() => {
const scannedDeviceSn = route.query.deviceCode;
if (scannedDeviceSn) {
deviceInfo.devsn = scannedDeviceSn;
}
});
return {
devTypes,
deviceTypeDialog,
deviceInfo,
showDeviceType,
clearInput,
onConfirm,
goBack,
deviceReg,
};
},
};
</script>
<style lang="scss" scoped>
.block-main {
height: auto;
overflow: hidden;
.head-wrap {
height: 0.96rem;
background: #31be7c;
font-family: Microsoft YaHei UI;
font-weight: 400;
color: #fff;
display: flex;
align-items: center;
.btn-cancel {
padding-left: 0.4rem;
padding-right: 0.4rem;
height: 0.96rem;
line-height: 0.96rem;
font-size: 0.36rem;
color: #fff;
}
.title {
font-size: 0.36rem;
text-align: center;
flex: 1;
}
.btn-sure {
width: 1.15rem;
height: 0.55rem;
background: #ffffff;
border-radius: 5px;
font-size: 0.36rem;
line-height: 0.55rem;
margin-right: 0.4rem;
margin-left: 0.4rem;
color: #31be7c;
}
}
.input-wrap {
height: 1.2rem;
line-height: 1.2rem;
border-bottom: 1px solid #ced6d2;
display: flex;
align-items: center;
.input {
flex: 1;
margin-left: 0.58rem;
font-size: 0.3rem;
width: 0px;
border-style: none;
outline: none;
height: 1rem;
text-align: left;
}
.icon-close {
width: 0.36rem;
height: 0.36rem;
margin-right: 0.4rem;
margin-left: 0.4rem;
}
.icon-arrow {
width: 0.2rem;
height: 0.3rem;
margin-left: 0.04rem;
margin-right: 0.4rem;
margin-left: 0.4rem;
}
}
.error-msg {
padding-left: 0.58rem;
margin-top: 0.19rem;
font-size: 0.24rem;
color: #ff6c00;
padding-right: 0.58rem;
text-align: left;
line-height: 0.24rem;
}
}
</style>效果圖

到此這篇關(guān)于Vue3使用vue-qrcode-reader實(shí)現(xiàn)掃碼綁定設(shè)備功能的文章就介紹到這了,更多相關(guān)Vue3掃碼綁定設(shè)備內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue使用v-viewer實(shí)現(xiàn)圖片預(yù)覽
這篇文章主要為大家詳細(xì)介紹了Vue使用v-viewer實(shí)現(xiàn)圖片預(yù)覽,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-10-10
Element-Plus表格實(shí)現(xiàn)Table自定義合并行數(shù)據(jù)
在開發(fā)項(xiàng)目中,我們時(shí)常會(huì)用到表格,許多需求可能會(huì)要求自定義特定的行或列,下面就跟隨小編一起來(lái)學(xué)習(xí)一下在實(shí)際開發(fā)中如何實(shí)現(xiàn)這一要求吧2024-12-12
vuejs實(shí)現(xiàn)折疊面板展開收縮動(dòng)畫效果
這篇文章主要介紹了vuejs實(shí)現(xiàn)折疊面板展開收縮動(dòng)畫效果,文中通過(guò)代碼給大家分享兩種情況介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-09-09
解決iView中時(shí)間控件選擇的時(shí)間總是少一天的問(wèn)題
下面小編就為大家分享一篇解決iView中時(shí)間控件選擇的時(shí)間總是少一天的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-03-03
vue3+pinia用戶信息持久緩存token的問(wèn)題解決
本文主要介紹了vue3+pinia用戶信息持久緩存token的問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
vue3項(xiàng)目打包成apk(android)詳細(xì)圖文教程
Vue本身是一個(gè)構(gòu)建用戶界面的漸進(jìn)式框架,不能直接打包成APK文件,但是你可以使用工具將Vue應(yīng)用打包成一個(gè)可以在Android設(shè)備上安裝的APK文件,這篇文章主要給大家介紹了關(guān)于vue3項(xiàng)目打包成apk(android)的相關(guān)資料,需要的朋友可以參考下2024-05-05

