欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

如何在H5页面中添加二维码扫描功能?Uniapp如何支持H5的扫码功能呢?

最编程 2024-02-22 07:48:36
...

本文主要使用html5-qrcode库实现二维码扫描功能,官方github地址:github.com/mebjas/html…

引入html5-qrcode:

npm i html5-qrcode

或者:

<script src="https://unpkg.com/html5-qrcode" type="text/javascript">

注意事项:

  1. 浏览器需要在https或者localhost下才能调用相机,关于本地调试如何启用https参考# 如何在本地启用https服务?
  2. 浏览器需要开启相机使用权限

基本使用

实例化html5-qrcode
<div id="reader"></div>
<script>
  // reader是DOM的id
  var html5QrCode = new Html5Qrcode("reader")
</script>
识别文件夹中的二维码图片
// 返回promise对象,imageFile,file对象,第二个参数:是否将图片显示到画布上
html5QrCode.scanFile(imageFile, true)
  .then(qr => {
    console.log(qr) // 二维码结果
  })
  .catch(err => {
    console.log(err) 
  })
扫码,利用相机进行扫码
// 获取相机设备
Html5Qrcode.getCameras()
  .then(devices => {
    // 扫码配置
    const config = {
      fps: 10, //  二维码扫描每秒帧数
      qrbox: { width: 300, height: 300 }, // UI框的大小
      aspectRatio: 1.777778,  // 纵横比,此值表示全屏
    }
    if (devices && devices.length) {
      const cameraId = devices[devices.length - 1].id //后置摄像头,一般最后一个是后置摄像头
      //let cameraId = devices[0].id //前置摄像头
      // 打开相机,开始扫描,callbackSuccess, callbackFailure扫描成功与失败的回调函数(自行定义)
      html5QrCode.start({ deviceId: { exact: cameraId } }, config, callbackSuccess, callbackFailure).catch(err => {
        alert(err)
      })
    } else {
      // 如果没有找到设备,直接启用摄像头
      //environment:后置摄像头  user:前置摄像头
      html5QrCode.start({ facingMode: "environment" }, config, onScanSuccess, onScanFailure).catch(err => {
        alert(err)
      })
    }
  })
  .catch(err => {
    alert(err)
  })
停止扫描
html5QrCode.stop()
清除画布
html5QrCode.clear()

vue中开发扫码页面

本次demo使用的是vue3,参考大多数扫码功能,都是以页面的形式展示,也可以封装为组件,主要看项目需求

思路:

  1. 点击扫描,跳转扫一扫页面,打开相机扫码
  2. 识别成功放回上一页,并将结果传递给上一页

实现效果:

主要实现代码:

demo源码:github.com/Abner105/sc…

ScanView.vue 扫码页面
  • 主要实现调起相机扫码,并返回结果到上一个页面
<template>
  <div>
    <div @click="close" class="title">扫码 X</div>
    <!-- 扫描仪占位符 -->
    <div id="reader"></div>
  </div>
</template>

<script setup>
import { Html5Qrcode } from "html5-qrcode"
import { onMounted } from "vue"
import { useRouter } from "vue-router"
import { onBeforeRouteLeave } from "vue-router"
const router = useRouter()
let html5QrCode = null
const scanRes = {} // 存放扫码结果

// 路由导航,将扫码结果放回给上一页
onBeforeRouteLeave(to => {
  to.query.scanRes = scanRes
})

// 关闭扫码页面
const close = () => {
  html5QrCode.stop().finally(() => {
    html5QrCode.clear()
    router.back()
  })
}

// // 扫码成功的回调
const onScanSuccess = qr => {
  scanRes.qr = qr
  close()
}

// 使用相机扫码
const useCamera = () => {
  // 实例化,接收元素id作为参数
  html5QrCode = new Html5Qrcode("reader")
  // 获取相机设备
  Html5Qrcode.getCameras()
    .then(devices => {
      // 扫码配置
      const config = {
        fps: 10, //  二维码扫描每秒帧数
        qrbox: { width: 300, height: 300 }, // UI框的大小
        aspectRatio: 1.777778,
        showTorchButtonIfSupported: true,
      }
      if (devices && devices.length) {
        let cameraId = devices[devices.length - 1].id //后置摄像头,一般最后一个是后置摄像头
        //let cameraId = devices[0].id //前置摄像头
        html5QrCode.start({ deviceId: { exact: cameraId } }, config, onScanSuccess).catch(err => {
          scanRes.err = err
          router.back()
        })
      } else {
        // 如果没有找到设备,直接启用摄像头
        //environment:后置摄像头  user:前置摄像头
        html5QrCode.start({ facingMode: "environment" }, config, onScanSuccess).catch(err => {
          scanRes.err = err
          router.back()
        })
      }
    })
    .catch(err => {
      scanRes.err = err
      router.back()
    })
}
onMounted(() => {
  useCamera()
})
</script>
HomeView.vue
  • 调起扫码页面,处理扫码结果
  • 选择二维码图片并识别二维码
<template>
  <div>
    <div class="title">Home</div>
    <button class="button">
      <input ref="inputRef" @change="useLocal" type="file" class="upload-input" accept="image/*" />
      <span>选择二维码</span>
      <div id="reader1"></div>
    </button>
    <button class="button" @click="useCamera">扫描二维码</button>
  </div>
</template>
<script setup>
import { onMounted } from "vue"
import { Html5Qrcode } from "html5-qrcode"
import { useRouter } from "vue-router"
import { useRoute } from "vue-router"
const router = useRouter()
const route = useRoute()

onMounted(() => {
  // 页面返回时,拿到扫码结果并处理
  const { qr, err } = route.query.scanRes || {}
  if (qr) {
    alert(qr) // 处理扫码成功结果
  } else if (err) {
    alert(err) // 处理失败结果
  }
})
  
// 选取二维码图片并识别
const useLocal = e => {
  if (e.target.files.length == 0) {
    return
  }
  const imageFile = e.target.files[0]
  const html5QrCode = new Html5Qrcode("reader1")
  html5QrCode.scanFile(imageFile, false)
    .then(qr => {
      alert(qr)
    })
    .catch(err => {
      alert(err)
    })
}

const useCamera = () => {
  router.push("/scan") // 去扫码页面
}
</script>
<style>
.title{
  height: 50px;
  line-height: 50px;
}
button{
  height: 50px;
  width: 120px;
}
</style>

uniapp中封装扫码页面

uniapp中uni.scanCode()可以调起扫码功能,但该API不兼容H5,因此H5页面还是需要自己写一个扫码页面。整体逻辑还是参考vueH5页面的实现。

实现效果:

demo代码:

当前uniapp项目中二维码图片识别功能使用的是reqrcode.js库,也可以使用html5-qrcode,这里我懒得改了。

pagexxx.vue 扫一扫入口页面

<image  src="/static/icon/scan.svg" @click="scancode"></image>
<script>
// #ifdef H5
const qrcode = require("@/utils/reqrcode.js") // 用于识别二维码图片
// #endif
export default {
  data() {
    return {
      // #ifdef H5
      scanResult: {}, // 扫码结果
      // #endif
    }
  },
  onShow() {
    // #ifdef H5
    if (this.scanResult.qr) {
      this.handleScan(this.scanResult.qr)
    } else if (this.scanResult.err) {
      uni.showToast({
        title: this.scanResult.err,
        duration: 2000,
        icon: "none",
      })
    }
    this.scanResult = {}
    // #endif
  },
  methods: {
    handleScan(address) {
      // 处理扫码逻辑
    },
    // 扫描二维码
    scancode() {
      let that = this
      // #ifdef APP-PLUS
      // APP使用uni自带的API
      uni.scanCode({
        scanType: ["qrCode"],
        success: res => {
          that.handleScan(res.result)
        },
      })
      // #endif
      // #ifdef H5
      uni.showActionSheet({
        itemList: ['扫描二维码', '选择二维码图片'],
        success(res) {
          if (!res.tapIndex) {
            // 去扫码页面
            uni.navigateTo({
              url: "/pages/scan/scan",
            })
          } else {
            // 选择二维码图片
            uni.chooseImage({
              count: 1,
              success: function (res) {
                const tempFilePaths = res.tempFilePaths
                qrcode.decode(tempFilePaths[0])
                qrcode.callback = function (img) {
                  if (img == "error decoding QR Code") {
                    uni.showToast({
                      title: "Incorrect QR code",
                      duration: 2000,
                      icon: "none",
                    })
                  } else {
                    that.handleScan(img)
                  }
                }
              },
            })
          }
        },
      })
      // #endif
    }
  }
}
</script>

san.vue 扫一扫页面

<template>
  <view>
    <!-- uView的自定义导航栏,背景设置为透明 -->
    <u-navbar
      :title="$t('common.scan')"
      @leftClick="closed"
      :titleStyle="{ fontWeight: '600', color: '#ffffff' }"
      bgColor="transparent"
      leftIconColor="#ffffff"
    ></u-navbar>
    <!-- 扫描仪占位符 -->
    <view id="reader"></view>
  </view>
</template>

<script>
import { Html5Qrcode } from "html5-qrcode"
export default {
  data() {
    return {
      html5QrCode: null,
    }
  },
  mounted() {
    this.useCamera() // 打开相机
  },
  methods: {
    // 关闭扫一扫页面,返回上一页
    closed() {
      this.html5QrCode.stop().finally(() => {
        this.html5QrCode.clear()
        uni.navigateBack()
      })
    },
    scanRes(qr, err) {
      // 修改上一个页面的数据,传递qr
      var pages = getCurrentPages()
      var prevPage = pages[pages.length - 2]
      prevPage.$vm.scanResult = { qr, err }
    },
    // 成功回调
    onScanSuccess(qr) {
      this.scanRes(qr)
      this.closed()
    },
    useCamera() {
      // 实例化,接收元素id作为参数
      this.html5QrCode = new Html5Qrcode("reader")
      // 获取相机设备
      Html5Qrcode.getCameras()
        .then(devices => {
          // 扫码配置
          const config = {
            fps: 10, //  二维码扫描每秒帧数
            qrbox: {
              width: 300,
              height: 300,
            }, // UI框的大小
            aspectRatio: 1.777778,
          }
          if (devices && devices.length) {
            let cameraId = devices[devices.length - 1].id //后置摄像头,一般最后一个是后置摄像头
            //let cameraId = devices[0].id //前置摄像头
            this.html5QrCode
              .start({ deviceId: { exact: cameraId, }, }, config, this.onScanSuccess)
              .catch(err => {
                this.scanRes(undefined, err)
                uni.navigateBack()
              })
          } else {
            // 如果没有找到设备,直接启用摄像头
            //environment:后置摄像头  user:前置摄像头
            this.html5QrCode
              .start( { facingMode: "environment" }, config, this.onScanSuccess )
              .catch(err => {
                this.scanRes(undefined, err)
                uni.navigateBack()
              })
          }
        })
        .catch(err => {
          this.scanRes(undefined, err)
          uni.navigateBack()
        })
    },
  },
}
</script>