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

最终效果

相关推荐
Larcher6 小时前
新手也能学会,100行代码玩AI LOGO
前端·llm·html
徐子颐6 小时前
从 Vibe Coding 到 Agent Coding:Cursor 2.0 开启下一代 AI 开发范式
前端
小月鸭6 小时前
如何理解HTML语义化
前端·html
jump6807 小时前
url输入到网页展示会发生什么?
前端
诸葛韩信7 小时前
我们需要了解的Web Workers
前端
brzhang7 小时前
我觉得可以试试 TOON —— 一个为 LLM 而生的极致压缩数据格式
前端·后端·架构
yivifu7 小时前
JavaScript Selection API详解
java·前端·javascript
这儿有一堆花7 小时前
告别 Class 组件:拥抱 React Hooks 带来的函数式新范式
前端·javascript·react.js
十二春秋8 小时前
场景模拟:基础路由配置
前端
六月的可乐8 小时前
实战干货-Vue实现AI聊天助手全流程解析
前端·vue.js·ai编程