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

最终效果

相关推荐
代码匠心11 小时前
AI 自动编程:一句话设计高颜值博客
前端·ai·ai编程·claude
_AaronWong12 小时前
Electron 实现仿豆包划词取词功能:从 AI 生成到落地踩坑记
前端·javascript·vue.js
cxxcode12 小时前
I/O 多路复用:从浏览器到 Linux 内核
前端
用户54330814419412 小时前
AI 时代,前端逆向的门槛已经低到离谱 — 以 Upwork 为例
前端
JarvanMo12 小时前
Flutter 版本的 material_ui 已经上架 pub.dev 啦!快来抢先体验吧。
前端
恋猫de小郭13 小时前
AI 可以让 WIFI 实现监控室内人体位置和姿态,无需摄像头?
前端·人工智能·ai编程
哀木13 小时前
给自己整一个 claude code,解锁编程新姿势
前端
程序员鱼皮13 小时前
GitHub 关注突破 2w,我总结了 10 个涨星涨粉技巧!
前端·后端·github
UrbanJazzerati13 小时前
Vue3 父子组件通信完全指南
前端·面试
是一碗螺丝粉13 小时前
5分钟上手LangChain.js:用DeepSeek给你的App加上AI能力
前端·人工智能·langchain