-
使用到的库
html5-qrcode
vant
vant
- 实现代码
<template>
<div>
<van-dialog
v-model:show="show"
title="扫一扫"
@close="closeDialog"
:show-cancel-button="true"
:show-confirm-button="false"
>
<div id="render" width="600px"></div>
</van-dialog>
<van-action-sheet
v-model:show="showAction"
:actions="actions"
:title="t('comm.toast.selectCamera')"
@select="onSelect"
:cancel-text="t('comm.cancel')"
close-on-click-action
/>
</div>
</template>
<script lang="ts" setup>
import { useLanguage } from "@/hooks/useLanguage";
import logger from "@/utils/Logger";
import ToastUtil from "@/utils/ToastUtil";
import { Html5Qrcode } from "html5-qrcode";
import { ActionSheetAction } from "vant";
import { nextTick, ref } from "vue";
const { t } = useLanguage();
export interface IScanCodeExpose {
scan(): void;
}
const emit = defineEmits(["scanTxt"]);
defineExpose<IScanCodeExpose>({
scan,
});
// 设备列表
const showAction = ref(false);
const actions = ref<ActionSheetAction[]>([]);
const decodeTxt = ref("");
function onSelect(val: any) {
logger.debug("选择项", val);
const cameraId = val.value;
show.value = true;
nextTick(() => {
html5QrCode.value = new Html5Qrcode("render", true);
html5QrCode.value
.start(
cameraId,
{
fps: 10, // Optional, frame per seconds for qr code scanning
qrbox: { width: 300, height: 300 }, // Optional, if you want bounded box UI
},
(decodedText, decodedResult) => {
decodeTxt.value = decodedText;
// do something when code is read
logger.debug("decodedText", decodedText);
logger.debug("decodedResult", decodedResult);
stopCameraScan();
},
(errorMessage) => {
// parse error, ignore it.
logger.debug("errorMessage", errorMessage);
},
)
.catch((err) => {
// Start failed, handle it.
logger.debug("err", err);
});
});
}
const show = ref(false);
const html5QrCode = ref<Html5Qrcode>();
function stopCameraScan() {
// 停止 QR 码扫描
html5QrCode.value
?.stop()
.then(() => {
logger.debug("QR Code scanning stopped.");
show.value = false;
html5QrCode.value?.clear();
ToastUtil.successToast("扫码成功");
emit("scanTxt", decodeTxt.value);
})
.catch((err) => {
logger.debug("Failed to stop scanning:", err);
});
}
function closeDialog() {
logger.debug("点击了关闭");
stopCameraScan();
show.value = false;
}
function getCameraId() {
Html5Qrcode.getCameras()
.then((devices) => {
/**
* devices would be an array of objects of type:
* { id: "id", label: "label" }
*/
logger.debug("设备列表devices:", devices);
actions.value = devices.map((item) => {
return {
name: item.label,
value: item.id,
};
});
showAction.value = true;
})
.catch((err) => {
logger.error(err);
})
.finally(() => {
ToastUtil.close();
});
}
function scan() {
logger.debug("打开扫码");
ToastUtil.loading(t("comm.toast.loading"));
getCameraId();
}
</script>
<style scoped lang="scss">
#reader {
min-height: 200px;
}
</style>
文章评论