123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- <script setup>
- import {Html5Qrcode, Html5QrcodeScanner, Html5QrcodeScanType, Html5QrcodeSupportedFormats} from "html5-qrcode";
- const emit = defineEmits('oSuccess', 'onError')
- const slots = useSlots();
- // 判断是否有 default 插槽
- const hasDefaultSlot = computed(() => !!slots.default);
- let isShow = ref(false)
- let results = ref(null)
- let scanInstance = null
- const openQrcode = async () => {
- Html5Qrcode.getCameras()
- .then(devices => {
- if (devices && devices.length) {// 当前环境下能识别出摄像头,并且摄像头的数据可能不止一个
- if (!scanInstance) {
- // reader 放置扫码功能的元素ID
- scanInstance = new Html5Qrcode('qr-reader', {
- formatsToSupport: [
- Html5QrcodeSupportedFormats.QR_CODE,
- ],
- })
- }
- isShow.value = true
- scanInstance.start(
- {facingMode: "environment"},
- {
- focusMode: 'continuous',
- fps: 1, // 可选,每n秒帧扫描一次
- qrbox: { // 扫描的UI框
- width: 250,
- height: 250
- },
- videoConstraints: {
- // width: 375,
- // height: (window.visualViewport.height - 50),
- aspectRatio: window.visualViewport.height / window.visualViewport.width,
- facingMode: "environment",
- }
- },
- (decodedText, decodedResult) => {
- showToast('识别成功')
- // 扫描结果
- results.value = {
- decodedText,
- decodedResult
- }
- isShow.value = false
- scanInstance.stop()
- emit('oSuccess', {
- decodedText,
- decodedResult
- })
- },
- (errorMessage, error) => {
- emit('onError', {
- errorMessage,
- error
- })
- }
- )
- }
- })
- .catch((err) => {
- isShow.value = false
- // 错误信息处理仅供参考,具体情况看输出!!!
- let errorStr = ''
- if (typeof err === "string") {
- errorStr = err
- } else {
- if (err.name === "NotAllowedError")
- errorStr = "您需要授予相机访问权限"
- if (err.name === "NotFoundError") {
- errorStr = "未检测到摄像头"
- }
- if (err.name === "NotSupportedError")
- errorStr = "摄像头访问只支持在安全的上下文中,如https或localhost"
- if (err.name === "NotReadableError") errorStr = "摄像头被占用"
- if (err.name === "OverconstrainedError")
- errorStr = "安装摄像头不合适"
- if (err.name === "StreamApiNotSupportedError")
- errorStr = "此浏览器不支持流API"
- }
- showToast(errorStr)
- })
- }
- const closeQrcode = () => {
- isShow.value = false
- if (scanInstance) scanInstance.stop()
- }
- let fileList = ref([])
- const uploadImg = () => {
- try {
- window.qrcode.callback = (result) => {
- showToast(result);
- };
- let file = state.fileList[0].file;
- let reader = new FileReader();
- reader.onload = (function () {
- return function (e) {
- window.qrcode.decode(e.target.result);
- };
- })(file);
- reader.readAsDataURL(file);
- } catch (error) {
- console.log(error);
- showToast({
- message: error+"识别失败!",
- duration: 2000,
- });
- }
- }
- const selectFile = ()=> {
- let odeScanner = new Html5QrcodeScanner(
- "qr-code-file", { fps: 1 , qrbox: { // 扫描的UI框
- width: 250,
- height: 250
- },});
- odeScanner.render((e) => {
- console.log(e)
- });
- console.log(odeScanner, 'odeScanner')
- }
- onMounted(() => {
- selectFile()
- })
- onUnmounted(() => {
- if (scanInstance) scanInstance.stop()
- })
- </script>
- <template>
- <div>
- <template v-if="hasDefaultSlot">
- <slot></slot>
- </template>
- <template v-else>
- <van-button @click="openQrcode" size="mini">扫一扫</van-button>
- </template>
- <div v-if="false" class="h-200">
- {{ results }}
- </div>
- <div class="overlay" v-show="isShow">
- <div class="absolute w-full z-30 flex flex-row items-center justify-center p-12">
- <div class="absolute left-12 font-bold" @click="closeQrcode">
- <span class="iconfont icon-left text-white"></span>
- </div>
- <div class="text-base text-[#fff] font-bold">
- 扫描二维码
- </div>
- </div>
- <div class="relative qr-reader z-20" id="qr-reader"></div>
- <p class="absolute w-full p-12 text-center bottom-100 z-30 text-sm text-[#fff]">请将二维码对准扫码框中心</p>
- <div id="qr-code-file" class="absolute w-54 h-54 grid place-items-center bottom-40 z-30 rounded-full bg-[#000]/80 text-white left-1/2 -translate-x-1/2">
- <img src="~/assets/img/scan/pic.png" height="32" width="32" alt=""/>
- </div>
- </div>
- <div id="qr-code-file" class="w-54 h-54 grid place-items-center bottom-40 z-30 rounded-full bg-[#000]/80 text-white">
- <img src="~/assets/img/scan/pic.png" height="32" width="32" alt=""/>
- </div>
- <van-uploader
- v-model="fileList"
- :preview-image="false"
- :after-read="uploadImg"
- accept="image/*"
- :multiple="false"
- :max-count="1"
- >
- <van-icon name="photo-o"
- /></van-uploader>
- </div>
- </template>
- <style scoped lang="scss">
- .overlay {
- position: fixed;
- bottom: 0;
- left: 0;
- z-index: 999999;
- width: 100%;
- height: calc(100% - 50px);
- background: rgba(0, 0, 0, 0.7);
- .scan-instruction {
- }
- }
- </style>
|