返回顶部
首页 > 资讯 > 前端开发 > JavaScript >Vue实现浏览器端扫码功能
  • 561
分享到

Vue实现浏览器端扫码功能

2024-04-02 19:04:59 561人浏览 薄情痞子
摘要

背景 不久前我做了关于获取浏览器摄像头并扫码识别的功能,本文中梳理了涉及到知识点及具体代码实现,整理成此篇文章内容。 本文主要介绍,通过使用基于 Vue 技术栈的前端开发技术,在浏

背景

不久前我做了关于获取浏览器摄像头并扫码识别的功能,本文中梳理了涉及到知识点及具体代码实现,整理成此篇文章内容。

本文主要介绍,通过使用基于 Vue 技术栈的前端开发技术,在浏览器端调起摄像头 📷,并进行扫码识别功能,对识别到的二维码进行跳转或其他操作处理。本文内容分为背景介绍、实现效果、技术简介、代码实现、总结等部分组成。

实现效果

本实例中主要有两个页面首页和扫码页,具体实现效果如下图所示。

  • 首页:点击 SCAN QRCODE 按钮,进入到扫码页。
  • 扫码页:首次进入时,或弹出 获取摄像头访问权限的系统提示框,点击允许访问,页面开始加载摄像头数据并开始进行二维码捕获拾取,若捕获到二维码,开始进行二维码解析,解析成功后加载识别成功弹窗。

 在线体验:https://draGonir.GitHub.io/h5-scan-qrcode

提示:需要在有摄像头设备的浏览器中竖屏访问。手机横竖屏检测小知识可前往我的另一篇文章《五十音小游戏中的前端知识》 中进行了解。

技术简介

WEBRTC api

WebRTC (Web Real-Time Communications) 是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间 点对点(Peer-to-Peer) 的连接,实现视频流和(或)音频流或者其他任意数据的传输。WebRTC 包含的这些标准使用户在无需安装任何插件或者第三方的软件的情况下,创建 点对点(Peer-to-Peer) 的数据分享和电话会议成为可能。

三个主要接口:

  • MediaStream:能够通过设备的摄像头及话筒获得视频、音频的同步流。
  • RtcpeerConnection:是 WebRTC 用于构建点对点之间稳定、高效的流传输的组件。
  • RTCDataChannel:使得浏览器之间建立一个高吞吐量、低延时的信道,用于传输任意数据。

🔗 前往 MDN 深入学习:WebRTC_API

WebRTC adapter

虽然 WebRTC规范已经相对健全稳固了,但是并不是所有的浏览器都实现了它所有的功能,有些浏览器需要在一些或者所有的WebRTC API上添加前缀才能正常使用。

WebRTC 组织在 github 上提供了一个WebRTC适配器(WebRTC adapter) 来解决在不同浏览器上实现 WebRTC 的兼容性问题。这个适配器是一个 javascript垫片,它可以让你根据 WebRTC 规范描述的那样去写代码,在所有支持 WebRTC 的浏览器中不用去写前缀或者其他兼容性解决方法。

🔗 前往 MDN 深入学习:WebRTC adapter

核心的API navigator.mediaDevices.getUserMedia

网页调用摄像头需要调用 getUserMedia APIMediaDevices.getUserMedia()会提示用户给予使用媒体输入的许可,媒体输入会产生一个 MediaStream,里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等等)、一个音频轨道(同样来自硬件或虚拟音频源,比如麦克风、A/D转换器 等等),也可能是其它轨道类型。

它返回一个Promise对象,成功后会 resolve 回调一个MediaStream对象;若用户拒绝了使用权限,或者需要的媒体源不可用,promisereject 回调一个PermissionDeniedError或者NotFoundError。(返回的 promise对象 可能既不会 resolve 也不会 reject,因为用户不是必须选择允许或拒绝。)

通常可以使用navigator.mediaDevices来获取MediaDevices,例如:


navigator.mediaDevices.getUserMedia(constraints)
  .then(function(stream) {
    // 使用这个stream
  })
  .catch(function(err) {
    // 处理error
  })

🔗 前往 MDN 深入学习:navigator.mediaDevices.getUserMedia

二维码解析库 jsQR

jsQR 是一个纯 JavaScript 二维码解析库,该库读取原始图像或者是摄像头,并将定位,提取和解析其中的任何 QR码

如果要使用 jsQR 扫描网络摄像头流,则需要 ImageData 从视频流中提取,然后可以将其传递给 jsQR

jsQR 导出一个方法,该方法接受 4 个参数,分别是解码的 图像数据 以及 可选的对象 进一步配置扫描行为。

imageData:格式为 [r0, g0, b0, a0, r1, g1, b1, a1, ...]Uint8ClampedArray( 8位无符号整型固定数组rgba 像素值。


const code = jsQR(imageData, width, height, options);
if (code) {
  console.log('找到二维码!', code);
}

🔗 前往 github 深入了解:jsQR

代码实现

流程

整个扫码流程如下图所示:页面初始化,先检查浏览器是否支持 mediaDevices 相关API,浏览器进行调去摄像头,调用失败,就执行失败回调;调用成功,进行捕获视频流,然后进行扫码识别,没有扫瞄到可识别的二维码就继续扫描,扫码成功后绘制扫描成功图案并进行成功回调。

下文内容对流程进行拆分,分别实现对应的功能。

扫码组件 Scaner

页面结构

我们先看下页面结构,主要由 4 部分组成:

  • 提示框。
  • 扫码框。
  • video:展示摄像头捕获视频流。
  • canvas: 绘制视频帧,用于二维码识别。

<template>
  <div class="scaner" ref="scaner">
    <!-- 提示框:用于在不兼容的浏览器中显示提示语 -->
    <div class="banner" v-if="showBanner">
      <i class="close_icon" @click="() => showBanner = false"></i>
      <p class="text">若当前浏览器无法扫码,请切换其他浏览器尝试</p>
    </div>
    <!-- 扫码框:显示扫码动画 -->
    <div class="cover">
      <p class="line"></p>
      <span class="square top left"></span>
      <span class="square top right"></span>
      <span class="square bottom right"></span>
      <span class="square bottom left"></span>
      <p class="tips">将二维码放入框内,即可自动扫描</p>
    </div>
    <!-- 视频流显示 -->
    <video
      v-show="showPlay"
      class="source"
      ref="video"
      :width="videoWH.width"
      :height="videoWH.height"
      controls
    ></video>
    <canvas v-show="!showPlay" ref="canvas" />
    <button v-show="showPlay" @click="run">开始</button>
  </div>
</template>

方法:绘制

  • 画线。
  • 画框(用于扫码成功后绘制矩形图形)。


// 画线
drawLine (begin, end) {
  this.canvas.beginPath();
  this.canvas.moveTo(begin.x, begin.y);
  this.canvas.lineTo(end.x, end.y);
  this.canvas.lineWidth = this.lineWidth;
  this.canvas.strokeStyle = this.lineColor;
  this.canvas.stroke();
},
// 画框
drawBox (location) {
  if (this.drawOnfound) {
    this.drawLine(location.topLeftCorner, location.topRightCorner);
    this.drawLine(location.topRightCorner, location.bottomRightCorner);
    this.drawLine(location.bottomRightCorner, location.bottomLeftCorner);
    this.drawLine(location.bottomLeftCorner, location.topLeftCorner);
  }
},

方法:初始化

  • 检查是否支持。
  • 调起摄像头。
  • 成功失败处理。


// 初始化
setup () {
  // 判断了浏览器是否支持挂载在MediaDevices.getUserMedia()的方法
  if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
    this.previousCode = null;
    this.parity = 0;
    this.active = true;
    this.canvas = this.$refs.canvas.getContext("2d");
    // 获取摄像头模式,默认设置是后置摄像头
    const facingMode = this.useBackCamera ? { exact: 'environment' } : 'user';
    // 摄像头视频处理
    const handleSuccess = stream => {
       if (this.$refs.video.srcObject !== undefined) {
        this.$refs.video.srcObject = stream;
      } else if (window.videoEl.mozSrcObject !== undefined) {
        this.$refs.video.mozSrcObject = stream;
      } else if (window.URL.createObjectURL) {
        this.$refs.video.src = window.URL.createObjectURL(stream);
      } else if (window.webkitURL) {
        this.$refs.video.src = window.webkitURL.createObjectURL(stream);
      } else {
        this.$refs.video.src = stream;
      }
      // 不希望用户来拖动进度条的话,可以直接使用playsinline属性,webkit-playsinline属性
      this.$refs.video.playsInline = true;
      const playPromise = this.$refs.video.play();
      playPromise.catch(() => (this.showPlay = true));
      // 视频开始播放时进行周期性扫码识别
      playPromise.then(this.run);
    };
    // 捕获视频流
    navigator.mediaDevices
      .getUserMedia({ video: { facingMode } })
      .then(handleSuccess)
      .catch(() => {
        navigator.mediaDevices
          .getUserMedia({ video: true })
          .then(handleSuccess)
          .catch(error => {
            this.$emit("error-captured", error);
          });
      });
  }
},

方法:周期性扫描


run () {
  if (this.active) {
    // 浏览器在下次重绘前循环调用扫码方法
    requestAnimationFrame(this.tick);
  }
},

方法:成功回调


// 二维码识别成功事件处理
found (code) {
  if (this.previousCode !== code) {
    this.previousCode = code;
  } else if (this.previousCode === code) {
    this.parity += 1;
  }
  if (this.parity > 2) {
    this.active = this.stopOnScanned ? false : true;
    this.parity = 0;
    this.$emit("code-scanned", code);
  }
},

方法:停止


// 完全停止
fullStop () {
  if (this.$refs.video && this.$refs.video.srcObject) {
    // 停止视频流序列轨道
    this.$refs.video.srcObject.getTracks().forEach(t => t.stop());
  }
}

方法:扫描

  • 绘制视频帧。
  • 扫码识别。


// 周期性扫码识别
tick () {
  // 视频处于准备阶段,并且已经加载足够的数据
  if (this.$refs.video && this.$refs.video.readyState === this.$refs.video.HAVE_ENOUGH_DATA) {
    // 开始在画布上绘制视频
    this.$refs.canvas.height = this.videoWH.height;
    this.$refs.canvas.width = this.videoWH.width;
    this.canvas.drawImage(this.$refs.video, 0, 0, this.$refs.canvas.width, this.$refs.canvas.height);
    // getImageData() 复制画布上制定矩形的像素数据
    const imageData = this.canvas.getImageData(0, 0, this.$refs.canvas.width, this.$refs.canvas.height);
    let code = false;
    try {
      // 识别二维码
      code = jsQR(imageData.data, imageData.width, imageData.height);
    } catch (e) {
      console.error(e);
    }
    // 如果识别出二维码,绘制矩形框
    if (code) {
      this.drawBox(code.location);
      // 识别成功事件处理
      this.found(code.data);
    }
  }
  this.run();
},

父组件

Scaner 的父组件主要加载页面,并展示 Scaner 扫码结果的回调。

页面结构


<template>
  <div class="scan">
    <!-- 页面导航栏 -->
    <div class="nav">
      <a class="close" @click="() => $router.go(-1)"></a>
      <p class="title">Scan QRcode</p>
    </div>
    <div class="scroll-container">
      <!-- 扫码子组件 -->
      <Scaner
        v-on:code-scanned="codeScanned"
        v-on:error-captured="errorCaptured"
        :stop-on-scanned="true"
        :draw-on-found="true"
        :responsive="false"
      />
    </div>
  </div>
</template>

父组件方法


import Scaner from '../components/Scaner';

export default {
  name: 'Scan',
  components: {
    Scaner
  },
  data () {
    return {
      errORMessage: "",
      scanned: ""
    }
  },
  methods: {
    codeScanned(code) {
      this.scanned = code;
      setTimeout(() => {
        alert(`扫码解析成功: $[code]`);
      }, 200)
    },
    errorCaptured(error) {
      switch (error.name) {
        case "NotAllowedError":
          this.errorMessage = "Camera permission denied.";
          break;
        case "NotFoundError":
          this.errorMessage = "There is no connected camera.";
          break;
        case "NotSupportedError":
          this.errorMessage =
            "Seems like this page is served in non-secure context.";
          break;
        case "NotReadableError":
          this.errorMessage =
            "Couldn't access your camera. Is it already in use?";
          break;
        case "OverconstrainedError":
          this.errorMessage = "Constraints don't match any installed camera.";
          break;
        default:
          this.errorMessage = "UNKNOWN ERROR: " + error.message;
      }
      console.error(this.errorMessage);
     alert('相机调用失败');
    }
  },
  mounted () {
    var str = navigator.userAgent.toLowerCase();
    var ver = str.match(/cpu iphone os (.*?) like Mac os/);
    // 经测试 iOS 10.3.3以下系统无法成功调用相机摄像头
    if (ver && ver[1].replace(/_/g,".") < '10.3.3') {
     alert('相机调用失败');
    }
  }

完整代码

🔗 github: Https://github.com/dragonir/h5-scan-qrcode

总结

应用扩展

我觉得以下几个功能都是可以通过浏览器调用摄像头并扫描识别来实现的,大家觉得还有哪些 很哇塞🌟 的功能应用可以通过浏览器端扫码实现 😂

  • 链接跳转。
  • 价格查询。
  • 登录认证。
  •  文件下载。

兼容性

  • 即使使用了 adaptergetUserMedia API 在部分浏览器中也存在不支持的。
  • 低版本浏览器(如 iOS 10.3 以下)、Android 小众浏览器(如 IQOO 自带浏览器)不兼容。
  • QQ微信 内置浏览器无法调用。

参考资料

[1]. Taking still photos with WebRTC

[2]. Choosing cameras in JavaScript with the mediaDevices API

[3]. 如何使用JavaScript访问设备前后摄像头

作者:dragonir 本文地址:https://www.cnblogs.com/dragonir/p/15405141.html

到此这篇关于Vue实现浏览器端扫码功能的文章就介绍到这了,更多相关vue浏览器扫码内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Vue实现浏览器端扫码功能

本文链接: https://lsjlt.com/news/154750.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Vue实现浏览器端扫码功能
    背景 不久前我做了关于获取浏览器摄像头并扫码识别的功能,本文中梳理了涉及到知识点及具体代码实现,整理成此篇文章内容。 本文主要介绍,通过使用基于 vue 技术栈的前端开发技术,在浏...
    99+
    2024-04-02
  • Vue PC前端扫码登录功能实现
    目录需求描述思路解析PC 扫码原理?前端功能实现如何生成二维码图片?如何控制二维码的时效性?前端如何获取服务器二维码的状态?参考资料:总结需求描述 目前大多数PC端应用都有配套的移动...
    99+
    2022-12-29
    vue扫码登录功能 vue登录功能 vue 扫码登录
  • Vue PC端怎么实现扫码登录功能
    本文小编为大家详细介绍“Vue PC端怎么实现扫码登录功能”,内容详细,步骤清晰,细节处理妥当,希望这篇“Vue PC端怎么实现扫码登录功能”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。.markdown-bod...
    99+
    2023-07-05
  • 详解Vue PC端如何实现扫码登录功能
    本篇文章给大家带来了关于Vue的相关知识,其中主要介绍了在PC端实现扫码的原理是什么?怎么生成二维码图片?怎么用Vue实现前端扫码登录?感兴趣的朋友,下面一起来看一下吧,希望对大家有帮助。.markdown-body{word-break:...
    99+
    2023-05-14
    前端 Vue.js
  • Vue使用PDF.js实现浏览pdf文件功能
    目录写在前面开始下载放入项目中制作组件使用写在前面 很头大 , 本来网络实际地址的 pdf 文件直接放在 iframe 的 src 中就可以浏览 pdf 文件的 , 但是对于虚拟地址...
    99+
    2023-05-16
    Vue PDF.js浏览pdf文件 Vue PDF.js pdf文件 Vue PDF.js
  • vue实现二维码扫码功能(带样式)
    需求: 利用vue实现二维码扫描; 插件: QRCodeReader; 插件下载 npm install --save vue-qrcode-reader 注意: 需要在https协...
    99+
    2024-04-02
  • Android实现扫码功能
    本文实例为大家分享了Android实现扫码功能的具体代码,供大家参考,具体内容如下 1、引入 implementation 'com.journeyapps:zxing-and...
    99+
    2024-04-02
  • VuePC端实现扫码登录功能示例代码
    目录需求描述思路解析前端功能实现如何控制二维码的时效性?前端如何获取服务器二维码的状态?本篇文章给大家带来了关于Vue的相关知识,其中主要介绍了在PC端实现扫码的原理是什么?怎么生成...
    99+
    2023-01-28
    Vue PC端扫码登录 Vue 扫码登录 vue登录功能
  • CSS怎么实现QQ浏览器功能
    这篇文章将为大家详细讲解有关CSS怎么实现QQ浏览器功能,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。知识点结合fullpage.js实现全屏滚动CSS中linear-gradient() 函数用于创建一...
    99+
    2023-06-08
  • 通过vue方式实现二维码扫码功能
    提示 这个插件只能在https协议下才能访问,http协议不好使,最好用vue2,vue3容易报错!!!!! 描述 通过vue的方式,实现扫码功能 参考文档:vue-qrcode-r...
    99+
    2024-04-02
  • android实现扫码枪功能
    扫码枪扫码效果等同于键盘录入,会回调dispatchKeyEvent键盘按下事件。 开发环境:有线扫码枪,支持二维码 代码 1. 接收数据 @Override ...
    99+
    2024-04-02
  • vue打印浏览器页面功能的两种实现方法
    目录方法一:通过npm 安装插件方法二:手动下载插件到本地总结推荐使用方法二 方法一:通过npm 安装插件 1,安装 npm install vue-print-nb --save...
    99+
    2023-05-15
    vue实现打印预览功能 vue实现打印预览功能 vue 打印预览
  • iOS实现PDF文件浏览功能
    写了一个小Demo,显示本地PDF格式文件,支持翻页、跳页、缩放。  先看一下效果图: iOS开发,显示PDF格式文件方法有很多: 最简单的应该是UIWebView...
    99+
    2022-05-18
    iOS PDF 文件浏览
  • vue怎么打印浏览器页面功能
    这篇文章主要介绍“vue怎么打印浏览器页面功能”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“vue怎么打印浏览器页面功能”文章能帮助大家解决问题。方法一:通过npm 安装插件1,安装 npm ins...
    99+
    2023-07-06
  • web浏览器端怎么实现
    这篇文章主要介绍“web浏览器端怎么实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“web浏览器端怎么实现”文章能帮助大家解决问题。浏览器端实现方案开发:大事件长图和专辑详情页大事件tab的视觉效...
    99+
    2023-06-04
  • 如何通过vue方式实现二维码扫码功能
    这篇文章主要为大家展示了“如何通过vue方式实现二维码扫码功能”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何通过vue方式实现二维码扫码功能”这篇文章吧。提示这个插件只能在https协议下才...
    99+
    2023-06-25
  • Flutter实现扫二维码功能
    本文实例为大家分享了Flutter实现扫二维码功能的具体代码,供大家参考,具体内容如下 首先在pubspec.yaml中添加: dependencies:   qrscan: ^0....
    99+
    2024-04-02
  • golang实现浏览器导出excel文件功能
    目录1.依赖包2.示例3.分析3.1先根据需求查询需要的list对象3.2新建文件,设置文件名,跟列名3.3设置标题单元格3.4设置内容单元格3.5流媒体返回web1.依赖包 imp...
    99+
    2024-04-02
  • C#怎么实现调用浏览器的功能
    本篇内容主要讲解“C#怎么实现调用浏览器的功能”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#怎么实现调用浏览器的功能”吧!C#调用浏览器之调用IE:System.Diagnostics.Pr...
    99+
    2023-06-17
  • Android实现网络图片浏览功能
    我们在上网的过程中经常看到各种图片,那你知道它是如何实现的吗?接下来就让我们一块探讨一下。 网络图片的浏览可以分为俩部分,基本的页面布局与界面交互,让我们一步步的来编写。 基本布局很简单,只需要有一个输入图片链接的EditText,一个浏览...
    99+
    2023-05-31
    android 图片浏览 roi
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作