首页 > 其他分享 >vue+zxing 扫描条形码

vue+zxing 扫描条形码

时间:2023-07-18 17:12:26浏览次数:43  
标签:条形码 vue scanner height width qr video rgba zxing

背景

扫描甲方商品身上的条形码。

吐槽下:这玩意又细又小,还反光,最后用的uni-app上的插件,而且不用自己封装了。虽然和我之前的二方案差不多,即使用

Quagga,打开video,将每帧画成canvas,然后转换为图片交给Quagga识别,缺点是功耗大,最后实装的表现还行,就是扫几个码,手机热了。

回归正题,最开始用的zxing,虽然后面测试发现ios部分手机没有聚焦,巨拉。但还是记录下怎么做的吧。

最下面是全部代码。

事前准备

安装zxing插件,--save是保存到package.json中, webrtc-adapter也是。

npm install @zxing/library --save
npm install webrtc-adapter --save

解释

zxing 是js插件,webrtc是引用手机设备用的具体查看mdn文档

MediaDevices.getUserMedia() - Web API 接口参考 | MDN (mozilla.org)

中间遇见的问题

zxing创建的video视频清晰度太低,然后用了webrtc创建,但兼容性有问题,查找文章,做了个兼容性判断,然后发现画面太小了。

碎碎念:其实是条形码太小了,还不清晰,颜色太淡。

最后发现在定义video属性的时候加zoom就可调整缩放,然后本人安卓redmK60好使,但ios不行。

参考文章

(66条消息) Vue 扫描二维码、条形码_vue扫一扫条形码功能_aibujin的博客-CSDN博客

代码

<template>
  <div class="scan-page">
    <!-- 扫码区域 -->
    <div class="video-box">
      <video ref="video" class="scan-video" id="video" autoplay></video>
    </div>
    <!-- 扫码样式 -->
    <div class="qr-scanner">
      <div class="box">
        <div class="line"></div>
        <div class="angle"></div>
      </div>
      <div class="back-arrow" @click="goBack">
        <span>返回</span>
      </div>
    </div>
  </div>
</template>
 
<script>
// WebRTC适配器 只需要引入就ok
import 'webrtc-adapter'
import { BrowserMultiFormatReader } from '@zxing/library';

export default {
  name: 'ScanCodePage',  // 扫码页面
  data() {
    return {
      codeReader: null,
      // tipShow: false,  // 是否展示提示
      tipMsg: '',  // 提示文本内容
      scanText: '',  // 扫码结果文本内容
      visible: false, //提示信息显示
      streaming: false, //初始化
      deviceId: null, //摄像头id
      video: null
    }
  },
  // 进入时的初始化
  async mounted() {

    let arr = [];
    this.codeReader = await new BrowserMultiFormatReader();
    navigator.mediaDevices.enumerateDevices()
      .then(function (devices) {
        devices.forEach(function (device) {
          if (device.kind === 'videoinput') {
            arr.push(device.deviceId)
          }
        });
      }).finally(res => {
        this.deviceId = arr[arr.length - 1]; //后置摄像头一般为最后一个,也可以在constraints中定义为后置摄像头,具体参数请查看mdn文档
        this.init();
      })
  },
  // 销毁时的还原
  beforeDestroy() {
    this.codeReader.reset();
    this.codeReader = null;
  },
  methods: {
    init() {  // 初始化摄像头
      this.video = document.querySelector('#video');
      let constraints = {
        video: {
          deviceId: this.deviceId,
          width: { min: 800, ideal: 1600 },
          height: { min: 600, ideal: 1200 },
          advanced: [
            { width: 1200, height: 900 },
            { aspectRatio: 1.33 }
          ],
          zoom: 3 //只有部分手机生效,苹果不生效
        }, audio: false
      }
      this.getUserMedia(constraints, this.getUserMediaSuccess, this.getUserMediaError)

      this.video.addEventListener('canplay', (ev) => {
        if (!this.streaming) {
          this.height = this.video.videoHeight / (this.video.videoWidth / this.width);
          if (isNaN(this.height)) {
            this.height = this.width / (4 / 3);
          }
          this.video.setAttribute('width', this.width);
          this.video.setAttribute('height', this.height);
          this.streaming = true;
        }
      }, false);

      this.decodeFromInputVideoFunc();
    },
    decodeFromInputVideoFunc() {  // 使用摄像头扫描
      this.codeReader.reset(); // 重置
      this.codeReader.decodeFromInputVideoDeviceContinuously(this.deviceId, 'video', (result, err) => {
        this.tipMsg = '正在尝试识别...';
        if (result) {
          console.log('扫码结果', result);
          this.scanText = result.text;
          alert(this.scanText)
          if (this.scanText) {
            this.visible = true
            alert(this.scanText+'==='+this.visible)

            console.log()
          }
        }
        console.log(err)
      }).catch(err => {
        console.log(err)
      });
    },
    // 浏览器适配 这个参考了简书上的文章,找不到原文了
    getUserMedia(constraints, success, error) {
      if (navigator.mediaDevices.getUserMedia) {
        //最新的标准API
        navigator.mediaDevices.getUserMedia(constraints).then(success).catch(error);
      } else if (navigator.webkitGetUserMedia) {
        //webkit核心浏览器
        navigator.webkitGetUserMedia(constraints, success, error)
      } else if (navigator.mozGetUserMedia) {
        //firfox浏览器
        navigator.mozGetUserMedia(constraints, success, error);
      } else if (navigator.getUserMedia) {
        //旧版API
        navigator.getUserMedia(constraints, success, error);
      }
    },
    //获取设备成功的方法
    getUserMediaSuccess(stream) {
      console.log(stream);
    },
    //获取设备失败的重写方法
    getUserMediaError(error) {
      console.log(`访问用户媒体设备失败${error.name}, ${error.message}`);
    },
    goBack() {  // 返回上一页
      this.$destroy();
      this.$router.go(-1);
    },
  }
}
</script>
 
<style lang="scss" scoped >

.video-box {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 90%;
  height: 20%;


}

.scan-video {
  width: 100%;
  height: 100%;
  object-fit: cover;

}

.scan-page {
  min-height: 100vh;
  background-color: #363636;




  .scan-tip {
    width: 100vw;
    position: fixed;
    bottom: 20px;
    left: 50%;
    transform: translateX(-50%);
    text-align: center;
    color: white;
    font-size: 5vw;
  }

  .qr-scanner {
    background-image: linear-gradient(0deg,
        transparent 24%,
        rgba(32, 255, 77, 0.1) 25%,
        rgba(32, 255, 77, 0.1) 26%,
        transparent 27%,
        transparent 74%,
        rgba(32, 255, 77, 0.1) 75%,
        rgba(32, 255, 77, 0.1) 76%,
        transparent 77%,
        transparent),
      linear-gradient(90deg,
        transparent 24%,
        rgba(32, 255, 77, 0.1) 25%,
        rgba(32, 255, 77, 0.1) 26%,
        transparent 27%,
        transparent 74%,
        rgba(32, 255, 77, 0.1) 75%,
        rgba(32, 255, 77, 0.1) 76%,
        transparent 77%,
        transparent);
    background-size: 0.3rem 0.3rem;
    background-position: -1rem -1rem;

    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 9;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
  }

  .qr-scanner .box {
    width: 90%;
    height: 20%;
    max-height: 75vh;
    max-width: 75vh;
    position: relative;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    overflow: hidden;
    border: 0.02rem solid rgba(0, 255, 51, 0.2);
  }

  .qr-scanner .line {
    height: calc(100% - 2px);
    width: 100%;
    background: linear-gradient(180deg, rgba(0, 255, 51, 0) 43%, #00ff33 211%);
    border-bottom: 3px solid #00ff33;
    transform: translateY(-100%);
    animation: radar-beam 2s infinite;
    animation-timing-function: cubic-bezier(0.53, 0, 0.43, 0.99);
    animation-delay: 1.4s;
  }

  .qr-scanner .box:after,
  .qr-scanner .box:before,
  .qr-scanner .angle:after,
  .qr-scanner .angle:before {
    content: '';
    display: block;
    position: absolute;
    width: 3vw;
    height: 3vw;
    border: 0.02rem solid transparent;
  }

  .qr-scanner .box:after,
  .qr-scanner .box:before {
    top: 0;
    border-top-color: #00ff33;
  }

  .qr-scanner .angle:after,
  .qr-scanner .angle:before {
    bottom: 0;
    border-bottom-color: #00ff33;
  }

  .qr-scanner .box:before,
  .qr-scanner .angle:before {
    left: 0;
    border-left-color: #00ff33;
  }

  .qr-scanner .box:after,
  .qr-scanner .angle:after {
    right: 0;
    border-right-color: #00ff33;
  }

  @keyframes radar-beam {
    0% {
      transform: translateY(-100%);
    }

    100% {
      transform: translateY(0);
    }
  }

  .back-arrow {
    position: fixed;
    top: 10px;
    left: 10px;
    width: 100px;
    height: 50px;
    // border-radius: 100%;
    // background-color: rgba(0, 0, 0, 0.3);
    font-size: 20px;
    z-index: 999;

    display: flex;
    justify-content: center;
    align-items: center;
    color: #fff;
  }

}
</style>

 

标签:条形码,vue,scanner,height,width,qr,video,rgba,zxing
From: https://www.cnblogs.com/piaohd/p/17563435.html

相关文章

  • vue使用hiprint实现打印(vue-plugin-hiprint)
    1、安装插件:npminstallvue-plugin-hiprint或yarnaddvue-plugin-hiprint2、普通使用:<template><divclass="box"><divclass="box-tool"><el-button-group><el-buttontype="primary......
  • vue v-if 和v-permission 共同使用的奇怪问题
    背景后台系统某功能按钮需要订单状态和用户权限共同校验是否显示,将权限校验和v-if共同作用在同一div中,下方为实例代码<divv-if="status==0"><div@click="function1">某按钮功能</div></div><divv-if="status==1"v-permission="['admin......
  • antd+vue3 tree-select 组件库 筛选结果不正确的问题
    第一次遇到这种带搜索框的下拉树状列表搜索关键字的时候出现我不想要的结果。我感觉组件它只是搜索一级列表而没有搜索二级列表,然后一节列表把它整个的二级列表带出来了。二级列表里边包含搜索关键字的所有item才是我想要的。相关代码:1<!--页面名称-->2<div......
  • vue 小写转大写方法
    好久好久没更新了啊,其实有好多可以写的,但是不知道为啥不想写了方法一://输入的金额进行大写转换functiontransformation(val){varfraction=["角","分"];vardigit=["零","壹","贰","叁","肆","伍","陆"......
  • vue前端项目启动
    我们拉取了一个前端项目后,如果项目中有说明的文档,可以参照文档的步骤启动项目,如果项目中没有说明文档,那我们可以按照以下的步骤启动项目1、首先是安装依赖包npminstall 2、启动项目npmrundev这里的npmrun环境名称,这里的环境名称主要取决于项目中的package.json文件中......
  • vue学习——分析脚手架
        ......
  • npm安装教程 搭建vue
    一、相关概念npm:Nodejs下的包管理器。webpack:它主要的用途是通过CommonJS的语法把所有浏览器端需要发布的静态资源做相应的准备,比如资源的合并和打包。vue-cli:用户生成Vue工程模板。(帮你快速开始一个vue的项目,也就是给你一套vue的结构,包含基础的依赖库,只需要npminstall......
  • 介绍社交论坛问答发帖系统源码-java+vue+uniapp开发前后端
    前后端分离社交论坛问答发帖BBS源码,社交论坛小程序|H5论坛|,app论坛是java+vue+uniapp开发的前后端分离社交论坛问答发帖/BBS项目,包括论坛图文帖,视频,圈子,IM私聊,微信支付,付费贴,积分签到,钱包充值等论坛小程序论坛app完整功能演示地址:www.runruncode.com/java/19462.html ......
  • 前端Vue仿微信我的菜单栏组件按钮组件
    随着技术的发展,开发的复杂度也越来越高,传统开发方式将一个系统做成了整块应用,经常出现的情况就是一个小小的改动或者一个小功能的增加可能会引起整体逻辑的修改,造成牵一发而动全身。通过组件化开发,可以有效实现单独开发,单独维护,而且他们之间可以随意的进行组合。大大提升开发效率......
  • vue--day27---vue生命周期1
              beforeCreate:数据监测、数据代理创建之前在实例初始化之后,数据监测、数据代理创建之前被调用,此时无法通过VM访问data中的数据、methods中的方法。created:数据监测、数据代理创建之后实例已经创建完成之后被调用,在这一步,实例已完成以下配......