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>
​

最终效果

相关推荐
慧一居士3 分钟前
flex 布局完整功能介绍和示例演示
前端
DoraBigHead5 分钟前
小哆啦解题记——两数失踪事件
前端·算法·面试
一斤代码6 小时前
vue3 下载图片(标签内容可转图)
前端·javascript·vue
中微子6 小时前
React Router 源码深度剖析解决面试中的深层次问题
前端·react.js
光影少年6 小时前
从前端转go开发的学习路线
前端·学习·golang
中微子6 小时前
React Router 面试指南:从基础到实战
前端·react.js·前端框架
3Katrina6 小时前
深入理解 useLayoutEffect:解决 UI "闪烁"问题的利器
前端·javascript·面试
前端_学习之路7 小时前
React--Fiber 架构
前端·react.js·架构
伍哥的传说7 小时前
React 实现五子棋人机对战小游戏
前端·javascript·react.js·前端框架·node.js·ecmascript·js
qq_424409198 小时前
uniapp的app项目,某个页面长时间无操作,返回首页
前端·vue.js·uni-app