实现浏览器扫一扫功能(移动端)

575 阅读1分钟

最近在做一个Vue3移动端项目,有涉及到浏览器实现扫一扫功能,实现的效果如下图

微信图片_20230509134453.jpg

实现原理

  1. 这里我们使用的是 jsQR
  • 安装
npm install jsqr -D
  • 使用
// 一定要是在https环境下才能使用jsqr
// 具体可以在vite.config.ts的defineConfig里配置server: {https: true}
import jsQR from 'jsqr'
  1. 创建生成 canvas 插入html标签
setDatas() {
      if (origin.indexOf('https') === -1) {
        // 判断是否为https环境
        alert('请在 https 环境中使用本插件。')
      }

      const windowWidth = window.screen.availWidth
      const windowHeight = window.screen.availHeight

      this.canvasWidth = windowWidth
      this.canvasHeight = windowHeight

      this.$nextTick(() => {
        this.video = document.createElement('video')
        this.c = document.createElement('canvas')
        this.c.id = 'c'
        this.c.width = this.canvasWidth
        this.c.height = this.canvasHeight
        this.c.style.width = '100%'
        document.querySelector('.canvasBox').append(this.c)
        this.openScan()
      })
    }
  1. 使用 MediaDevices.getUserMedia() API调用本地摄像头实现录像以及拍照功能
openScan() {
    const videoParam = {
        audio: false,
        video: {
          // 调用后摄像头
          facingMode: {exact:'environment'},
          width,
          height
        }
      }
      navigator.mediaDevices
        .getUserMedia(videoParam)
        .then((stream) => {
          this.video.srcObject = stream
          this.video.setAttribute('playsinline', true)
          this.video.play()
          // 浏览器内置方法
          requestAnimationFrame(this.tick);
          [this.track] = stream.getVideoTracks()
          setTimeout(() => {
            // 控制是否关闭闪光灯
            this.isUseTorch = this.track.getCapabilities().torch || null
          }, 500)
        })
        .catch((err) => {
          alert('设备不支持,请检查是否允许摄像头权限')
          console.log(err)
        })
}
  1. 通过 jsQR 拿到二维码或条形码里的内容
tick() {
      if (this.video.readyState === this.video.HAVE_ENOUGH_DATA) {
        this.canvasHeight = this.video.videoHeight
        this.canvasWidth = this.video.videoWidth
        this.c.width = this.canvasWidth
        this.c.height = this.canvasHeight
        if (this.canvas2d === undefined) {
          this.canvas2d = this.c.getContext('2d')
        }

        this.canvas2d.drawImage(
          this.video,
          0,
          0,
          this.canvasWidth,
          this.canvasHeight
        )

        const imageData = this.canvas2d.getImageData(
          0,
          0,
          this.canvasWidth,
          this.canvasHeight
        )

        const code = jsQR(imageData.data, imageData.width, imageData.height, {
          inversionAttempts: 'dontInvert'
        })

        if (code) {
          this.drawLine(
            code.location.topLeftCorner,
            code.location.topRightCorner,
            '#FF3B58'
          )
          this.drawLine(
            code.location.topRightCorner,
            code.location.bottomRightCorner,
            '#FF3B58'
          )
          this.drawLine(
            code.location.bottomRightCorner,
            code.location.bottomLeftCorner,
            '#FF3B58'
          )
          this.drawLine(
            code.location.bottomLeftCorner,
            code.location.topLeftCorner,
            '#FF3B58'
          )
          if (code.data) {
            this.getQrCode(code.data)
          }
        }
      }
      requestAnimationFrame(this.tick)
    },
    getQrCode(val) {
      // 这里 val 就是二维码的内容,这里可以根据自己项目的需求处理内容
      alert(JSON.stringify(val))
    }

最终效果展示

微信图片_20230509141057.jpg

如发现更好的方法,欢迎大家留言~