Vue

Vue3 - H5项目 扫描二维码

芸殇
2024-04-29 / 0 评论 / 203 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2024年05月06日,已超过908天没有更新,若内容或图片失效,请留言反馈。

开发环境、组件库

  • Vue3
  • @zxing/library
  • Vant
  • 注意 !!! @zxing/library插件只能运行在https环境下或localhost

Vue3 本地开启Https

如何在Vue3 项目中开启本地 Https 可以看这篇文章 Vue3 开启Https

安装

npm install @zxing/library

代码

<script setup>
import { ref, reactive, onMounted, onUnmounted } from "vue"
import { BrowserMultiFormatReader } from "@zxing/library"
// 我对 Vant 库的 Dialog 组件做了二次封装
import { useDialog } from "@/hooks/useDialog.ts"
// ref组件
const videoRef = ref()
const reader = ref()
// 初始化摄像头
const init = () => {
  reader.value = new BrowserMultiFormatReader()
  reader.value.listVideoInputDevices().then(res => {
    // res 是当前手机的摄像头数据,是一个数组
    let backDevice
    // 这里对res的数量作判定,如果小于等于0,则证明该设备没有摄像头
    if (res.length > 0) {
      // 获取到后置摄像头
      backDevice = findBackDevice(res)
    }else {
      useDialog({
        title: "未检测到摄像头",
        showCancel: false,
        success: () => {
          window.history.back();
        }
      });
    }
    // 重置摄像头
    reader.value.reset()
    // 获取摄像头ID
    let videoId = backDevice?.deviceId
    // 参数分别是 摄像头ID video标签 回调函数
    reader.value.decodeFromVideoDevice(videoId, videoRef.value, res => {
      // 判断是否扫描到数据,扫描到数据会产生res
      if (res) {
        // res.text 为扫描二维码的url
      }
    })
  }
}
const findBackDevice = (value) => {
  let backDevice
  // 对获取到的摄像头数据进行遍历
  for (let i = 0; i < value.length; i++) {
    // 找到后置摄像头
    if (value[i].label.indexOf("back") > -1) return backDevice = item
  }
  return backDevice
}
// 这个函数是对url的query参数进行拆分
const analyzeUrl = (url) => {
  let urlQueryArray = url.split('?')[1]
  urlQueryArray = urlQueryArray.split('&')
  const query = {}
  urlQueryArray.forEach(item => {
    let itemSplit = item.split('=')
    query[itemSplit[0]] = itemSplit[1]
  })
  return query
}
onMounted(() => {
  initScan()
})
onUnmounted(() => {
  reader.value.reset()
})
</script>
<template>
  <div class="scan-page">
    <div class="scan-box">
      <!-- 扫码所需要的video标签 -->
      <video ref="videoRef" class="scan-video" autoplay></video>
      <div class="scan-scanner">
        <div class="scan-scanner-box">
          <div class="scan-scanner-line"></div>
          <div class="scan-scanner-angle"></div>
        </div>
      </div>
    </div>
  </div>
</template>
<style lang="less" scoped>
.scan-box {
  position: fixed;
  top: 0;
  left: 0;
  height: 100%;
  width: 100vw;
  background-image: linear-gradient(
    0deg,
    transparent 24%,
    rgba(32, 255, 77, 0.1) 25%,
    rgba(32, 255, 77, 0.1) 26%,
    transparent 27%,
    transparent 74%,
    rgba(32, 255, 77, 0.1) 75%,
    rgba(32, 255, 77, 0.1) 76%,
    transparent 77%,
    transparent
  ),
  linear-gradient(
    90deg,
    transparent 24%,
    rgba(32, 255, 77, 0.1) 25%,
    rgba(32, 255, 77, 0.1) 26%,
    transparent 27%,
    transparent 74%,
    rgba(32, 255, 77, 0.1) 75%,
    rgba(32, 255, 77, 0.1) 76%,
    transparent 77%,
    transparent
  );
  background-size: 3px 3px;
  background-position: -1px -1px;
}
.scan-video {
  height: 100vh;
  width: 100vw;
  object-fit: cover;
}
.scan-scanner {
  .scan-scanner-box {
    width: 213px;
    height: 213px;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    overflow: hidden;
    border: 1px solid rgba(0, 255, 51, 0.2);
    ::after {
      .pseudo-content;
      .pseudo-content-top;
      right: 0;
      border-right-color: #00ff33;
    }
    ::before {
      .pseudo-content;
      .pseudo-content-top;
      left: 0;
      border-left-color: #00ff33;
    }
  }
  .scan-scanner-line {
    height: calc(100% - 2px);
    width: 100%;
    background: linear-gradient(180deg, rgba(0, 255, 51, 0) 43%, #00ff33 211%);
    border-bottom: 3px solid #00ff33;
    transform: translateY(-100%);
    animation: radar-beam 2s infinite alternate;
    animation-timing-function: cubic-bezier(0.53, 0, 0.43, 0.99);
    animation-delay: 1.4s;
    ::after {
      .pseudo-content;
      .pseudo-content-bottom;
      right: 0;
      border-right-color: #00ff33;
    }
    ::before {
      .pseudo-content;
      .pseudo-content-bottom;
      left: 0;
      border-left-color: #00ff33;
    }
  }
  .scan-pseudo-content {
    content: "";
    display: block;
    position: absolute;
    width: 3vw;
    height: 3vw;
    border: 2px solid transparent;
  }
  .pseudo-content-top {
    top: 0;
    border-top-color: #00ff33;
  }
  .pseudo-content-bottom {
    bottom: 0;
    border-bottom-color: #00ff33;
  }
}
@keyframes radar-beam {
  0% {
    transform: translateY(-100%);
  }
  100% {
    transform: translateY(0);
  }
}
.scan-page {
  overflow-y: hidden;
}
</style>
0

评论 (0)

取消