文章目录

  • vue-qrcode-reader
  • html5-qrcode
  • 介绍
  • 使用
  • 页面调用


vue-qrcode-reader

vue-qrcode-reader主要依赖Stream API,不支持Vue Native

  1. 下载vue-qrcode-reader插件:npm install vue-qrcode-reader
  2. 引入QrcodeStream调用摄像头扫码(还提供了拍照或选择相册扫码,看个人需求)
  3. 调用init(初始化摄像机)和decode(返回二维码编码的字符串)/ detect(在decode之前触发;还会返回相机框架内二维码的坐标)方法

注意:

  1. Chrome需要Https或本地主机环境
  2. 在Chrome浏览器中,不能第二次提示用户访问相机权限,一旦拒绝,只能手动授予权限
    不支持:彩色反转二维码(深色背景、浅色前景)、Model 1 二维码。
<template>
  <div style="height: 100%; width: 100%">
    <MyHeader :name="'扫码'" left="arrow-left" @goBackEv="$emit('goBack')" />
    <qrcode-stream
      :key="_uid"
      :track="this.paintBoundingBox"
      @decode="onDecode"
      @init="onInit"
    /> 
  </div>
</template>

<script>
import { QrcodeStream } from 'vue-qrcode-reader'
export default {
  components: { QrcodeStream },
  methods: {
    onDecode(result) {
      console.log('扫码结果', result)
      this.$emit('goBack', result)
    },
    async onInit(promise) {
      try {
        await promise
      } catch (error) {
        if (error.name === 'NotAllowedError') {
          // ERROR: you need to grant camera access permission
          this.$toast("您需要授予摄像机访问权限")
        } else if (error.name === 'NotFoundError') {
          // ERROR: no camera on this device
          this.$toast("这个设备上没有摄像头")
        } else if (error.name === 'NotSupportedError') {
          // ERROR: secure context required (HTTPS, localhost)
          this.$toast("需要安全上下文(HTTPS, localhost)")
        } else if (error.name === 'NotReadableError') {
          // ERROR: is the camera already in use?
          this.$toast("摄像机已经在使用了吗?")
        } else if (error.name === 'OverconstrainedError') {
          // ERROR: installed cameras are not suitable
          this.$toast("安装的摄像头不合适")
        } else if (error.name === 'StreamApiNotSupportedError') {
          // ERROR: Stream API is not supported in this browser
          this.$toast("此浏览器不支持流API")
        } else if (error.name === 'InsecureContextError') {
          // ERROR: Camera access is only permitted in secure context. 
          // Use HTTPS or localhost rather than HTTP.
          this.$toast(`摄像头只能在安全环境下使用。使用HTTPS或本地主机,而不是HTTP`)
        } else {
          this.$toast(`ERROR: Camera error (${error.name})`)
        }
      }
    },
    /** 追踪二维码的样式
	* 注意: 避免访问这个函数中的变量、计算属性以及vuex,该函数是每秒调用,会造成内存泄漏
	* detectedCodes:位置对象
	* ctx:CanvasRenderingContext2D实例
   	*/
    paintBoundingBox(detectedCodes, ctx) {
      for (const detectedCode of detectedCodes) {
        const { boundingBox: { x, y, width, height } } = detectedCode
        ctx.lineWidth = 2
        ctx.strokeStyle = '#007bff'
        ctx.strokeRect(x, y, width, height)
      }
    }
  }
}
</script>
 
<style>
</style>

效果

怎么获取 ACCESS_TOKEN_vue.js

html5-qrcode

介绍

html5-qrcode是轻量级和跨平台的QR码和条形码扫码的JS库,集成二维码、条形码和其他一些类型的代码扫描功能,代码依赖于Zxing-js
优势:

  1. 支持扫描不同类型的条形码和二维码
  2. 支持不同平台,Android、IOS、MacOS、Windows或Linux
  3. 支持不同的浏览器,如Chrome、Firefox、Safari、Edge
  4. 支持相机扫描以及本地文件
  5. 附带一个端到端库与UI以及一个低级库,以建立自己的UI
  6. 支持自定义,如闪光/火炬支持、缩放等

使用

  1. 下载html5-qrcode插件: npm install html5-qrcode
  2. 添加一个元素,作为一个占位符的二维码扫描仪(高度由摄像机的视频馈送的纵横比得出)
    <div id="reader" width="375px"></div>

注意:直接访问摄像头,涉及到隐私,所以环境必须是https

<template>
  <div style="height: 100%; width: 100%">
    <MyHeader :name="'调用摄像头扫码'" left="arrow-left" @goBackEv="$emit('goBack')" />
    <div class="qrcode">
      <div id="reader"></div>
    </div>
  </div>
</template>

<script>
import { Html5Qrcode } from "html5-qrcode"
export default {
  components: { QrcodeStream },
  data() {
    return {
      html5QrCode: null
    }
  },
  created() {
    this.getCameras()
  },
  beforeDestroy() {
    if (this.html5QrCode) this.stop()
  },
  methods: {
    getCameras() {
      Html5Qrcode.getCameras()
        .then((devices) => {
          if (devices && devices.length) {
            this.html5QrCode = new Html5Qrcode("reader")
            this.start()
          }
        })
        .catch((err) => {
          // handle err
          this.html5QrCode = new Html5Qrcode("reader")
          this.$toast('您需要授予相机访问权限')
        })
    },
    start() {
      this.html5QrCode
        .start(
       	  // environment后置摄像头 user前置摄像头
          { facingMode: "environment" },
          {
            fps: 2, // 可选,每秒帧扫描二维码
            qrbox: { width: 250, height: 250 }, // 可选,如果你想要有界框UI
            // aspectRatio: 1.777778 // 可选,视频馈送需要的纵横比,(4:3--1.333334, 16:9--1.777778, 1:1--1.0)传递错误的纵横比会导致视频不显示
          },
          (decodedText, decodedResult) => {
            // do something when code is read
            console.log('decodedText', decodedText);
            console.log('decodedResult', decodedResult);
            this.$emit("goBack", decodedText)
          }
        )
        .catch((err) => {
          console.log('扫码错误信息', err);
          // 错误信息处理仅供参考,具体情况看输出!!!
          if (typeof err == 'string') {
            this.$toast(err)
          } else {
            if (err.name == 'NotAllowedError') return this.$toast("您需要授予相机访问权限")
            if (err.name == 'NotFoundError') return this.$toast('这个设备上没有摄像头')
            if (err.name == 'NotSupportedError') return this.$toast('摄像头访问只支持在安全的上下文中,如https或localhost')
            if (err.name == 'NotReadableError') return this.$toast('相机被占用')
            if (err.name == 'OverconstrainedError') return this.$toast('安装摄像头不合适')
            if (err.name == 'StreamApiNotSupportedError') return this.$toast('此浏览器不支持流API')
          }
        })
    },
    stop() {
      this.html5QrCode.stop().then((ignore) => {
        // QR Code scanning is stopped.
        console.log("QR Code scanning stopped.")
      })
        .catch((err) => {
          // Stop failed, handle it.
          console.log("Unable to stop scanning.")
        })
    },
  }
}
</script>
 
<style lang="less" scoped>
.qrcode {
  position: relative;
  height: 100%;
  width: 100%;
  background-color: rgba(0, 0, 0, 0.1);
}
#reader {
  top: 20%;
  left: 0;
}
</style>

效果

怎么获取 ACCESS_TOKEN_vue.js_02

怎么获取 ACCESS_TOKEN_二维码_03

页面调用

<template>
	<div>
		<div v-if="isStart ">
			<!-- 页面其他结构 -->
		</div>
		<ScanView
	      v-else
	      @goBack="getScanResult"
	    />
	</div>
</template>

<script>
	import ScanView from '@/components/scanView/index.vue'
	export default {
		data() {
		    return {
		      isStart : false
		    }
		},
		components: { ScanView },
		methods: {
			getScanResult(result) {
		      console.log('接收扫码结果', result)
		      if (result) {
		        // 处理逻辑
		      }
		      this.isStart = false
		    },
		}
	}
</script>