一、开发前的准备

    实现二维码或条形码的扫描识别比较普遍的做法是去调用微信 JS-SDK 的扫一扫功能(详见 概述 | 微信开放文档),或者支付宝 H5 开放的API(详见 支付宝H5开放文档)。

    但是这两者都会比较麻烦且有一定的局限性,微信的扫一扫只能在微信里用,而且还需要公众号认证等配置操作。支付宝在内置 App 内可以同时识别二维码和条形码,但外部调用的 API 无法一次性同时识别,只能分开识别。

    我这里就提供一个直接使用的开源库https://github.com/zxing-js/library,本人移动端前端开发的框架是 Vue,组件库用的是 Vant,本文方案只要开发时用的电脑具有摄像头就可以实现效果预览。

二、实现效果图

这里分享两个在线工具

1、免费在线条形码生成器-条码生成制作工具

2、草料二维码生成器

    可以看到这样操作不用经过任何打包(有的需要打包成 app 才行)、部署(有的需要部署到 https 的服务器才行)、配置(前面说的诸如微信开发的配置等...)。

三、具体操作实现

1、安装。

npm install @zxing/library --save

 2、假设场景:页面上有个按钮,点击触发扫码功能 @click='scanCode()',在 methods 写入该方法。

scanCode() {
  console.log('浏览器信息', navigator.userAgent);
  this.$router.push({
    path: '/ScanCodePage'
  });
}

同时在 vue-router 写入对应页面的路由。

{ 
  title: '扫码页面', 
  name: 'ScanCodePage', 
  path: '/ScanCodePage', 
  component: () => import('@/views/ScanCodePage.vue') 
}

3、扫码页面代码,通过与 video 标签结合使用,把以下代码直接全部拷贝到新建的一个 ScanCodePage.vue 文件里使用,读者在注释的地方自行根据需求,编写后续的业务代码即可。

<template>
  <div class="scan-page">
    <!-- 返回导航栏 -->
    <van-nav-bar title="扫描二维码/条形码" left-text="取消" left-arrow 
      fixed class="scan-index-bar" @click-left="clickIndexLeft()"
    ></van-nav-bar>
    <!-- 扫码区域 -->
    <video ref="video" id="video" class="scan-video" autoplay></video>
    <!-- 提示语 -->
    <div v-show="tipShow" class="scan-tip">{{ tipMsg }}</div>
  </div>
</template>
 
<script>
import { BrowserMultiFormatReader } from '@zxing/library';
import { Toast, Dialog, Notify } from 'vant';
 
  export default {
    name: 'ScanCodePage',  // 扫码页面
    data() {
      return {
        codeReader: null,
        tipShow: false,  // 是否展示提示
        tipMsg: '',  // 提示文本内容
        scanText: '',  // 扫码结果文本内容
      }
    },
    created() {
      this.openScan();
    },
    watch: {
      '$route'(to, from) {
        if(to.path == '/ScanCodePage'){  // 当处于该页面时
          this.openScan();
        }
      }
    },
    destroyed(){
      this.codeReader.reset();
      this.codeReader = null;
    },
    methods: {
      async openScan() {  // 初始化摄像头
        this.codeReader = await new BrowserMultiFormatReader();
        this.codeReader.getVideoInputDevices().then(videoDevices => {
          this.tipMsg = '正在调用摄像头...';
          this.tipShow = true;
          console.log('get-videoDevices', videoDevices);

          // 默认获取摄像头列表里的最后一个设备id,通过几部测试机发现一般前置摄像头位于列表里的前面几位,所以一般获取最后一个的是后置摄像头
          let firstDeviceId = videoDevices[videoDevices.length - 1].deviceId; 
          // 一般获取了手机的摄像头列表里不止一个,有的手机摄像头高级多层,会有变焦摄像头等情况,需要做处理
          if (videoDevices.length > 1) {
            // 一般通过判断摄像头列表项里的 label 字段,'camera2 0, facing back' 字符串含有 'back' 和 '0',大部分机型是这样,如果有些机型没有,那就还是默认获取最后一个
            firstDeviceId = videoDevices.find(el => { return el.label.indexOf('back') > -1 && el.label.indexOf('0') > -1 }) ? 
              videoDevices.find(el => { return el.label.indexOf('back') > -1 && el.label.indexOf('0') > -1 }).deviceId : 
              videoDevices[videoDevices.length - 1].deviceId;
          }
          console.log('get-firstDeviceId', firstDeviceId);

          this.decodeFromInputVideoFunc(firstDeviceId);
        }).catch(err => {
          this.tipShow = false;
          console.error(err);
        });
      },
      decodeFromInputVideoFunc(firstDeviceId) {  // 使用摄像头扫描
        this.codeReader.reset(); // 重置
        this.codeReader.decodeFromInputVideoDeviceContinuously(firstDeviceId, 'video', (result, err) => {
          this.tipMsg = '正在尝试识别...';
          if (result) {
            console.log('扫码结果', result);
            this.scanText = result.text;
            if (this.scanText) {
              this.tipShow = false;
              Dialog.confirm({  // 获取到扫码结果进行弹窗提示,这部分接下去的代码根据需要,读者自行编写了
                title: '扫码结果',
                message: this.scanText,
              }).then(() => {  // 点击确认

              }).catch(() => {  // 点击取消

              });
            }
          }
        });
      },
      clickIndexLeft(){  // 返回上一页
        this.$destroy();
        this.$router.go(-1);
        // window.location.href = document.referrer;
      }
    }
  }
</script>
 
<style lang="scss">
.scan-index-bar{
  background-image: linear-gradient( -45deg, #42a5ff ,#59cfff);
  .van-nav-bar__title, .van-nav-bar__arrow, .van-nav-bar__text{
    color: #fff !important;
  }
}
.scan-page{
  min-height: 100vh;
  background-color: #363636;
  overflow-y: hidden;
  .scan-video{
    height: 85vh;
  }
  .scan-tip{
    width: 100vw;
    text-align: center;
    color: white;
    font-size: 5vw;
  }
}
</style>

    这是我本人在工作学习中做的一些总结,同时也分享出来给需要的小伙伴哈 ~ 供参考学习,有什么建议也欢迎评论留言,转载请注明出处哈,感谢支持!

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐