vue实现h5扫码

插件 html5-qrcode npm地址

html5-qrcode是一个基于JavaScript 轻量级和跨平台的扫码插件。允许用户使用摄像头扫描二维码,并且解析为文本或者url。

  • 支持扫描不同类型的二维码和条形码
  • 支持不同的平台,Android、IOS、Windows、MacOs或者linux
  • 支持不同的浏览器,Chrome、Safari、Edge等
  • 支持扫描本地文件

访问摄像头涉及用户隐私,所以访问环境必须在https下

实现(该代码环境基于vue3)

  1. 安装依赖

    npm install html5-qrcode
    
  2. 引入

    javascript 复制代码
    import { Html5Qrcode } from 'html5-qrcode'
  3. 使用

    • setup数据

      php 复制代码
         const state = reactive({
            html5QrCode: null,
             fileList:[]
          })
    • 判断当前环境下是否有摄像头

      scss 复制代码
      Html5Qrcode.getCameras()
      .then(devices =>{
          if(devices &&devices.length){
              // 当前环境下能识别出摄像头,并且摄像头的数据可能不止一个
               state.html5QrCode = new Html5Qrcode('reader')         //  reader  放置扫码功能的元素ID
              startInit()
         }
      })
      .catch(() =>{
         // 摄像头无访问权限
      })
    • 扫码

      ini 复制代码
      const startInit = () =>{
            state.html5QrCode.start(
                //  environment后置摄像头 user前置摄像头
                {facingMode:'environment'},
                {
                    fps:1, // 可选,每n秒帧扫描一次
                    qrbox:{
                        width:250,
                        height:250
                    } // 扫描的   UI框
                },
                (decodedText, decodedResult) =>{
                    // 扫描结果
                }
            )
          .catch((err) =>{
                // 扫码错误信息
                let message = ''
                if(typeof err == 'string'){
                    message = '识别失败'
                }else {
                  if (err.name == 'NotAllowedError') {
                    message = '您需要授予相机访问权限!'
                  }
                  if (err.name == 'NotFoundError') {
                    message = '这个设备上没有摄像头!'
                  }
                  if (err.name == 'NotSupportedError') {
                    message = '摄像头访问只支持在安全的上下文中,如https或localhost!'
                  }
                  if (err.name == 'NotReadableError') {
                    message = '相机被占用!'
                  }
                  if (err.name == 'OverconstrainedError') {
                    message = '安装摄像头不合适!'
                  }
                  if (err.name == 'StreamApiNotSupportedError') {
                    message = '此浏览器不支持流API!'
                  }
                }
            })
      }
  4. 停止扫码

    javascript 复制代码
    const stop = () => {
          state.html5QrCode
            .stop()
            .then((ignore) => {
              console.log('停止扫码', ignore)
            })
            .catch((err) => {
              console.log(err)
              showToast('停止扫码失败')
            })
        }
  5. 识别本地文件

    javascript 复制代码
      const dealSelectFiles = () => {
          try {
            window.qrcode.callback = (result) => {
                // 识别成功
            }
            // get select files.
            let file = state.fileList[0].file
            var reader = new FileReader()
            reader.onload = (function () {
              return function (e) {
                window.qrcode.decode(e.target.result)
              }
            })(file)
            reader.readAsDataURL(file)
          } catch (error) {
             // 识别失败
          }
        }
  6. 在离开页面时要停止扫码功能

    scss 复制代码
      onUnmounted(() => {
          //扫描设备是否在运行
          if (state.html5QrCode.isScanning) {
            stop()
          }
        })

完整代码

xml 复制代码
<template>
  <div class="scanCode">
    <div class="container">
      <div class="qrcode">
        <div id="reader"></div>
      </div>
    </div>
    <div class="btn">
      <div class="left-back">
        <van-icon name="arrow-left" @click="clickBack" />
      </div>
​
      <div class="right-file">
        <van-uploader v-model="fileList" :preview-image="false" :after-read="dealSelectFiles">
          <van-icon name="photo-o" />
        </van-uploader>
      </div>
    </div>
  </div>
</template>
​
<script>
import { reactive } from 'vue'
import { defineComponent, toRefs, onMounted, onUnmounted } from 'vue'
import { Html5Qrcode } from 'html5-qrcode'
import { showToast, } from 'vant'
export default defineComponent({
  setup() {
    const state = reactive({
      html5QrCode: null,
      fileList: [],
    })
​
​
    const start = () => {
      state.html5QrCode
        .start(
          { facingMode: 'environment' },
          {
            fps: 1, 
            qrbox: { width: 250, height: 250 } 
          },
          (decodedText, decodedResult) => {
            console.log('decodedText', decodedText)
            console.log('decodedResult', decodedResult)
          }
        )
        .catch((err) => {
          console.log('扫码错误信息', err)
          let message = ''
          // 错误信息处理仅供参考,具体描述自定义
          if (typeof err == 'string') {
            message = '二维码识别失败!'
          } else {
            if (err.name == 'NotAllowedError') {
              message = '您需要授予相机访问权限!'
            }
            if (err.name == 'NotFoundError') {
              message = '这个设备上没有摄像头!'
            }
            if (err.name == 'NotSupportedError') {
              message = '摄像头访问只支持在安全的上下文中,如https或localhost!'
            }
            if (err.name == 'NotReadableError') {
              message = '相机被占用!'
            }
            if (err.name == 'OverconstrainedError') {
              message = '安装摄像头不合适!'
            }
            if (err.name == 'StreamApiNotSupportedError') {
              message = '此浏览器不支持流API!'
            }
          }
        })
    }
​
    const getCameras = () => {
      Html5Qrcode.getCameras()
        .then((devices) => {
          if (devices && devices.length) {
            state.html5QrCode = new Html5Qrcode('reader')
            start()
          }
        })
        .catch((err) => {
 
          showToast({
            message: '摄像头无访问权限!',
            duration: 3000
          })
        
    }
​
    const stop = () => {
      state.html5QrCode
        .stop()
        .then((ignore) => {
          console.log('停止扫码', ignore)
        })
        .catch((err) => {
          console.log(err)
          showToast('停止扫码失败')
        })
    }
​
    const dealSelectFiles = () => {
      try {
        window.qrcode.callback = (result) => {
           showToast('成功了,结果是:' + result)
        }
        // get select files.
        let file = state.fileList[0].file
        var reader = new FileReader()
        reader.onload = (function () {
          return function (e) {
            window.qrcode.decode(e.target.result)
          }
        })(file)
        reader.readAsDataURL(file)
      } catch (error) {
        showToast({
          message: '图片识别失败!',
          duration: 3000
        })
      }
    }
​
  
    onMounted(() => {
      getCameras()
    })
​
​
    onUnmounted(() => {
      //扫描设备是否在运行
      if (state.html5QrCode.isScanning) {
        stop()
      }
    })
    return {
      ...toRefs(state),
      getCameras,
      dealSelectFiles,
    }
  }
})
</script>
​
<style lang="scss" scoped>
.scanCode {
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: rgba(0, 0, 0);
}
.container {
  height: 90vh;
  position: relative;
  width: 100%;
}
​
.qrcode {
  height: 100%;
}
#reader {
  top: 50%;
  left: 0;
  transform: translateY(-50%);
}
​
.btn {
  flex: 1;
  padding: 3vw;
  display: flex;
  justify-content: space-around;
  color: #fff;
  font-size: 8vw;
  align-items: flex-start;
}
</style>
​

最终效果

相关推荐
一个处女座的程序猿O(∩_∩)O1 小时前
小型 Vue 项目,该不该用 Pinia 、Vuex呢?
前端·javascript·vue.js
hackeroink4 小时前
【2024版】最新推荐好用的XSS漏洞扫描利用工具_xss扫描工具
前端·xss
迷雾漫步者6 小时前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-6 小时前
验证码机制
前端·后端
燃先生._.7 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖8 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235248 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240259 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar9 小时前
纯前端实现更新检测
开发语言·前端·javascript