vue3.0, vue2.0项目h5,pc端实现扫描二维码(qrcode-reader-vue3 , @zxing/library和vue-qrcode-reader)

扫码二维码的方法

  1. 第一微信jssdk自带的扫一扫功能,
    • 优点:无兼容性问题,只要微信能扫一扫的场景,这个api都能扫。
    • 缺点:只能在微信环境使用,浏览器环境中不能使用,另外一点,需要后端配合出接口,获取当前公众号的appid等信息。
  2. 直接用原生插件实现,发现两种插件 vue-qrcode-reader 和 @zxing/library,两个插件都可以在项目中使用,

    vue-qrcode-reader在苹果手机中无法使用,第一次扫码无反应调不起摄像头,需要返回第二次进入才会正常(暂未找到解决方法),
    @zxing/library安卓ios都能正常调用起摄像头,但是对于华为手机,因为华为手机有6个摄像头,正常手机就2个摄像头,所以对于华为手机要兼容判断下
    如果二维码参数太多,生成的二维码密度就会越多,正常大小扫不出来,所以需要放大二维码,参数不能传太多,影响扫码准确性

    1. @zxing/library 和vue-qrcode-reade 库兼容问题
      在装有 iOS < 14.3 相机访问仅适用于本机 Safari,而不适用于其他浏览器 (Chrome,…) 或使用 UIWebView 或 WKWebView 的应用。这不是这个库的限制,而是苹果有限的 WebRTC 支持的限制,
      但是 iOS 14.3(2020 年 12 月发布)现在也支持第三方浏览器中的 WebRTC。
      浏览器层使用的是 MediaDevices Web API,这是旧版浏览器不支持的。
      您可以使用 WebRTC 适配器等外部 polyfill 来增加浏览器兼容性。
      该库使用的是 TypedArray 等,这在较旧的浏览器(例如 Android 4 默认浏览器)中不可用。
      Int32ArrayUint8ClampedArray您可以使用 core-js 添加对这些浏览器的支持

qrcode-reader-vue3

  1. 安装指令
    npm install --save qrcode-reader-vue3
    
  2. 组件中使用
    <template>
      <div class="scan">
        <qrcode-stream
          :camera="camera"
          @decode="onDecode"
          @init="onInit"
          style="height: 100vh;"
        >
          <div>
            <div class="qr-scanner">
              <div class="box">
                <div class="line"></div>
                <div class="angle"></div>
              </div>
            </div>
          </div>
        </qrcode-stream>
      </div>
    </template>
    
    <script lang="ts" scope>
    import { QrcodeStream } from "qrcode-reader-vue3";
    import { defineComponent, ref, onMounted } from "vue";
    export default defineComponent({
      components: { QrcodeStream },
      setup(props) {
       let camera = ref<any>();
       let error = ref<string>('');
       //回调扫描结果
       function onDecode(result) {
       	// 扫码结果
        console.log(result)
          if (result !== "") {
           
          }
        }
        // 检查是否调用摄像头
        async function onInit(promise) {
          try {
            const { capabilities } = await promise;
            console.log(capabilities);
          } catch (error) {
            if (error.name === "NotAllowedError") {
              error = "ERROR: 您需要授予相机访问权限";
            } else if (error.name === "NotFoundError") {
              error = "ERROR: 这个设备上没有摄像头";
            } else if (error.name === "NotSupportedError") {
              error = "ERROR: 所需的安全上下文(HTTPS、本地主机)";
            } else if (error.name === "NotReadableError") {
              error = "ERROR: 相机被占用";
            } else if (error.name === "OverconstrainedError") {
              error = "ERROR: 安装摄像头不合适";
            } else if (error.name === "StreamApiNotSupportedError") {
              error = "ERROR: 此浏览器不支持流API";
            } else if (error.name === "InsecureContextError") {
              error =
                "ERROR: 仅允许在安全上下文中访问摄像机。使用HTTPS或本地主机,而不是HTTP。";
            } else {
              error = "ERROR:摄像机错误";
            }
          }
        }
        return {
          camera,
          onDecode,
          onInit,
        };
      },
    });
    </script>
    

注:运行在vue3.0环境,
vue-qrcode-reader再vue3.0中不生效

@zxing/library

  1. 安装指令
    npm install @zxing/library
    
  2. 项目中使用
    <template>
      <div class="QrCode">
        <video ref="video" height="100%" width="100%" id="video" autoplay></video>
      </div>
      <div class="Qr_scanner">
        <div class="box">
          <div class="line_row">
            <div class="line"></div>
          </div>
          <div class="angle"></div>
        </div>
      </div>
    </template>
    
    <script lang="ts" scope>
    import { BrowserMultiFormatReader } from "@zxing/library";
    import {
      defineComponent,
      reactive,
      onBeforeUnmount,
      onMounted,
    } from "vue";
    export default defineComponent({
      setup(props) {
    
        let codeReader = reactive(new BrowserMultiFormatReader());
        onMounted(() => {
          openScan();
        });
        function openScan() {
          codeReader
            .getVideoInputDevices()
            .then((videoInputDevices) => {
              console.log("videoInputDevices", videoInputDevices, "摄像头设备");
              // 默认获取第一个摄像头设备id
              let firstDeviceId = videoInputDevices[0].deviceId;  // 根据id选择摄像头
              if (videoInputDevices.length > 1) {
                // 华为手机有6个摄像头,前三个是前置,后三个是后置,第6个摄像头最清晰
                if (videoInputDevices.length > 5) {
                  firstDeviceId = videoInputDevices[5].deviceId;
                } else {
                  // 判断是否后置摄像头
                  if (videoInputDeviceslablestr.indexOf("back") > -1) {
                    firstDeviceId = videoInputDevices[0].deviceId;
                  } else {
                    firstDeviceId = videoInputDevices[1].deviceId;
                  }
                }
              }
              decodeFromInputVideoFunc(firstDeviceId);
              
            })
            .catch((err) => {
              alert(err)
            });
        };
    
        let decodeFromInputVideoFunc = (firstDeviceId: any) => {
          codeReader.decodeFromInputVideoDeviceContinuously(
            firstDeviceId,    // firstDeviceId  为null 时默认选择面向环境的摄像头
            "video",
            (result: any, err) => {
              if (result) {
                alert(result);
                console.log(result, "扫描结果");
              }
              if (err && !err) {
                console.error(err);
              }
            }
          );
        };
    
        onBeforeUnmount(() => {
          codeReader.reset();
        });
        return {
          codeReader,
        };
      },
    });
    </script>
    
    <style scoped>
    .QrCode {
      width: 100vw;
      height: 100vh;
      background: rgba(0, 0, 0, 0.2);
      /* background: red; */
      position: relative;
    }
    #video {
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
    
    /* // 二维码动画 */
    
    .Qr_scanner {
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      z-index: 9;
    
      width: 100%;
      height: 100%;
      position: relative;
      background-color: rgba(0, 0, 0, 0.5);
    }
    
    .Qr_scanner .box {
      width: 75vw;
      height: 75vw;
      max-height: 75vh;
      max-width: 75vh;
      position: relative;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      overflow: hidden;
      border: 1px solid rgb(43, 113, 254);
    
    }
    .line_row {
      width: 100%;
      overflow: hidden;
    
      background-image: linear-gradient(
          0deg,
          transparent 24%,
          rgba(136, 176, 255, 0.1) 25%,
          rgba(136, 176, 255, 0.1) 26%,
          transparent 27%,
          transparent 74%,
          rgba(136, 176, 255, 0.1) 75%,
          rgba(136, 176, 255, 0.1) 76%,
          transparent 77%,
          transparent
        ),
        linear-gradient(
          90deg,
          transparent 24%,
          rgba(136, 176, 255, 0.1) 25%,
          rgba(136, 176, 255, 0.1) 26%,
          transparent 27%,
          transparent 74%,
          rgba(136, 176, 255, 0.1) 75%,
          rgba(136, 176, 255, 0.1) 76%,
          transparent 77%,
          transparent
        );
      background-size: 3rem 3rem;
      background-position: -1rem -1rem;
      animation: Heightchange 2s infinite;
      animation-timing-function: cubic-bezier(0.53, 0, 0.43, 0.99);
      animation-delay: 1.4s;
      border-bottom: 1px solid rgba(136, 176, 255, 0.1);
      display: flex;
      justify-content: center;
      align-items: flex-end;
    }
    
    .Qr_scanner .line {
      
      width: 100%;
      height: 3px;
      background: #2b71fe;
      filter: blur(4px);
    }
    
    .Qr_scanner .box:after,
    .Qr_scanner .box:before,
    .Qr_scanner .angle:after,
    .Qr_scanner .angle:before {
      content: "";
      display: block;
      position: absolute;
      width: 78px;
      height: 78px;
    
      border: 0.3rem solid transparent;
    }
    
    .Qr_scanner .box:after,
    .Qr_scanner .box:before {
      top: -7px;
      border-top-color: #2b71fe;
    }
    
    .Qr_scanner .angle:after,
    .Qr_scanner .angle:before {
      bottom: -7px;
      border-bottom-color: #2b71fe;
    }
    
    .Qr_scanner .box:before,
    .Qr_scanner .angle:before {
      left: -7px;
      border-left-color: #2b71fe;
    }
    
    .Qr_scanner .box:after,
    .Qr_scanner .angle:after {
      right: -7px;
      border-right-color: #2b71fe;
    }
    
    @keyframes radar-beam {
      0% {
        transform: translateY(-100%);
      }
    
      100% {
        transform: translateY(0);
      }
    }
    @keyframes Heightchange {
      0% {
        height: 0;
      }
    
      100% {
        height: 100%;
      }
    }
    </style>
    
    注:如果报错:Can’t enumerate devices, method not supported.
    扫码能运行在https,和本地上(用http://localhost:8080/,,不要用IP:192.168.xx.xx:8080)
    可以运行中vue3.0和vue2.0环境中
  3. 相机授权的时候可以点击拒绝,拒绝后就不能够在调取了
    ZXing 库本身并不直接提供重新获取权限的专用 API。通常,JavaScript 库是无法直接在用户拒绝权限后重新触发权限请求的。
    调用原生的相机监听方法:
    调起相机之前先看一下用户有没有授权,如果没有授权就让他重新进入页面进行授权
    navigator.mediaDevices.getUserMedia({ video: true })
    .then(stream => {
     // 用户授权了相机权限,可以进行后续操作
       console.log('相机已授权')
       decodeFromInputVideoFunc(firstDeviceId);
     })
     .catch(err => {
       // 处理错误,可能是因为权限被拒绝
       console.log('获取相机权限失败:', err);
     });
    

vue-qrcode-reader

  1. 安装指令
    npm install vue-qrcode-reader
    
  2. 组件中的应用
    <template>
      <div class="scan">
        <qrcode-stream
          :camera="camera"
          @decode="onDecode"
          @init="onInit"
          style="height: 100vh;"
        >
          <div>
            <div class="qr-scanner">
              <div class="box">
                <div class="line"></div>
                <div class="angle"></div>
              </div>
            </div>
          </div>
        </qrcode-stream>
      </div>
    </template>
    <script>
    // 引入
    import { QrcodeStream } from "vue-qrcode-reader";
    export default {
      // 注册
      components: { QrcodeStream },
      data() {
        return {
          camera: "auto",
          result: "", // 扫码结果信息
          error: "" // 错误信息
        };
      },
      created() {},
      methods: {
        //回调扫描结果
        onDecode(result) {
          if (result !== "") {
            this.$emit("ok", result);
          }
        },
        // 检查是否调用摄像头
        async onInit(promise) {
          try {
            const { capabilities } = await promise;
            console.log(capabilities);
          } catch (error) {
            if (error.name === "NotAllowedError") {
              this.error = "ERROR: 您需要授予相机访问权限";
            } else if (error.name === "NotFoundError") {
              this.error = "ERROR: 这个设备上没有摄像头";
            } else if (error.name === "NotSupportedError") {
              this.error = "ERROR: 所需的安全上下文(HTTPS、本地主机)";
            } else if (error.name === "NotReadableError") {
              this.error = "ERROR: 相机被占用";
            } else if (error.name === "OverconstrainedError") {
              this.error = "ERROR: 安装摄像头不合适";
            } else if (error.name === "StreamApiNotSupportedError") {
              this.error = "ERROR: 此浏览器不支持流API";
            } else if (error.name === "InsecureContextError") {
              this.error =
                "ERROR: 仅允许在安全上下文中访问摄像机。使用HTTPS或本地主机,而不是HTTP。";
            } else {
              this.error = "ERROR:摄像机错误";
            }
    
            this.$emit("err", this.error);
          }
        }
      }
    };
    </script>
    <style scoped>
    </style>
    
  • 19
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值