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

最终效果

相关推荐
华玥作者16 小时前
[特殊字符] VitePress 对接 Algolia AI 问答(DocSearch + AI Search)完整实战(下)
前端·人工智能·ai
Mr Xu_17 小时前
告别冗长 switch-case:Vue 项目中基于映射表的优雅路由数据匹配方案
前端·javascript·vue.js
前端摸鱼匠17 小时前
Vue 3 的toRefs保持响应性:讲解toRefs在解构响应式对象时的作用
前端·javascript·vue.js·前端框架·ecmascript
lang2015092817 小时前
JSR-340 :高性能Web开发新标准
java·前端·servlet
好家伙VCC18 小时前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
未来之窗软件服务18 小时前
未来之窗昭和仙君(六十五)Vue与跨地区多部门开发—东方仙盟练气
前端·javascript·vue.js·仙盟创梦ide·东方仙盟·昭和仙君
嘿起屁儿整19 小时前
面试点(网络层面)
前端·网络
VT.馒头19 小时前
【力扣】2721. 并行执行异步函数
前端·javascript·算法·leetcode·typescript
phltxy20 小时前
Vue 核心特性实战指南:指令、样式绑定、计算属性与侦听器
前端·javascript·vue.js
Byron070721 小时前
Vue 中使用 Tiptap 富文本编辑器的完整指南
前端·javascript·vue.js