vue移动端实现调用相机扫描二维码或条形码

发布时间 2023-05-09 21:22:41作者: IT小姐姐

一、首先下载需要的插件

npm install @zxing/library --save

二、假设场景:页面上有个按钮,点击触发扫码功能 @click='scanCode()',在 methods 写入该方法。

scanCode() {
  console.log('浏览器信息', navigator.userAgent);
  this.$router.push({
    path: '/qrcode'
  });
}

三、在 vue-router 写入对应页面的路由。

{ 
  title: '扫码页面', 
  name: 'Qrcode', 
  path: '/qrcode', 
  component: () => import('@/views/qrcode.vue') 
}

四、扫码页面代码,通过与 video 标签结合使用,把以下代码直接全部拷贝到新建的一个 qrcode.vue 文件里使用

<template>
  <div class="page-scan">
    <!--返回-->
    <van-nav-bar
      title="扫描二维码"
      :fixed="true"
      :placeholder="true"
      left-arrow
      @click-left="onClickLeft"
    />
    <!-- 扫码区域 -->
    <video ref="video" id="video" class="scan-video" autoplay></video>
    <!-- 提示语 -->
    <div v-show="tipShow" class="scan-tip">{{ tipMsg }}</div>
  </div>
</template>
 
<script>
import { BrowserMultiFormatReader } from "@zxing/library";
export default {
  name: "scanCodePage",
  data() {
    return {
      loadingShow: false,
      codeReader: null,
      scanText: "",
      vin: null,
      tipMsg: "正在尝试识别....",
      tipShow: false,
    };
  },
  created() {
    this.codeReader = new BrowserMultiFormatReader();
    this.codeReader.reset();
    this.openScan();
  },
  beforeDestroy() {
    document.getElementById("video").srcObject.getTracks()[0].stop();
  },
  watch: {
    $route(to, from) {
      if (to.path == "/scanCodePage") {
        this.codeReader = new BrowserMultiFormatReader();
        this.openScanTwo();
      }
    },
  },
  methods: {
    async openScan() {
      this.codeReader
        .getVideoInputDevices()
        .then((videoInputDevices) => {
          this.tipShow = true;
          this.tipMsg = "正在调用摄像头...";
          // 默认获取第一个摄像头设备id
          let firstDeviceId = videoInputDevices[0].deviceId;
          // 获取第一个摄像头设备的名称
          const videoInputDeviceslablestr = JSON.stringify(
            videoInputDevices[0].label
          );
          if (videoInputDevices.length > 1) {
            // 判断是否后置摄像头
            if (videoInputDeviceslablestr.indexOf("back") > -1) {
              firstDeviceId = videoInputDevices[0].deviceId;
            } else {
              firstDeviceId = videoInputDevices[1].deviceId;
            }
          }
          this.decodeFromInputVideoFunc(firstDeviceId);
        })
        .catch((err) => {
          this.tipShow = false;
          console.error(err);
        });
    },
    async openScanTwo() {
      this.codeReader = await new BrowserMultiFormatReader();
      this.codeReader
        .getVideoInputDevices()
        .then((videoInputDevices) => {
          this.tipShow = true;
          this.tipMsg = "正在调用摄像头...";
          // 默认获取第一个摄像头设备id
          let firstDeviceId = videoInputDevices[0].deviceId;
          // 获取第一个摄像头设备的名称
          const videoInputDeviceslablestr = JSON.stringify(
            videoInputDevices[0].label
          );
          if (videoInputDevices.length > 1) {
            // 判断是否后置摄像头
            if (videoInputDeviceslablestr.indexOf("back") > -1) {
              firstDeviceId = videoInputDevices[0].deviceId;
            } else {
              firstDeviceId = videoInputDevices[1].deviceId;
            }
          }
          this.decodeFromInputVideoFunc(firstDeviceId);
        })
        .catch((err) => {
          this.tipShow = false;
          console.error(err);
        });
    },
    decodeFromInputVideoFunc(firstDeviceId) {
      this.codeReader.reset(); // 重置
      this.scanText = "";
      this.codeReader.decodeFromInputVideoDeviceContinuously(
        firstDeviceId,
        "video",
        (result, err) => {
          this.tipMsg = "正在尝试识别...";
          this.scanText = "";
          if (result) {
           //这里是扫码后的结果,具体怎么用要看项目需求
          }
          if (err && !err) {
            this.tipMsg = "识别失败";
            setTimeout(() => {
              this.tipShow = false;
            }, 2000);
            console.error(err);
          }
        }
      );
    },
    onClickLeft() {
      document.getElementById("video").srcObject.getTracks()[0].stop();
      setTimeout(() => {
        this.$router.back();
      }, 200);
    },
  },
};
</script>
 
<style lang="less" scoped>
/deep/.van-nav-bar__title {
  font-size: 18px;
  font-weight: 800;
}
/deep/ .van-nav-bar .van-icon {
  color: #333;
  font-size: 24px;
}
.scan-video {
  height: 80vh;
  width: 100%;
}
.scan-tip {
  text-align: center;
  margin-bottom: 10vh;
  color: white;
  font-size: 5vw;
}
.page-scan {
  overflow-y: hidden;
  background-color: #363636;
}
</style>