当前位置: 首页 > news >正文

手机 浏览器调用摄像头扫描二维码Quagga

注:需用谷歌浏览器才能调用权限

1. 引入依赖:npm install @ericblade/quagga2

<template><el-button color="#188ae2" @click="handleScan" class="scan-btn" :disabled="isInitializing || isScanning">{{t('btn.scan') }}</el-button><!-- 条形码扫描器的占位符 --><div id="interactive" ref="interactiveRef" class="viewport" style="display: none;"></div></template><script setup>import { ref, onBeforeUnmount } from 'vue'
import Quagga from '@ericblade/quagga2'; // 引用
const interactiveRef = ref < HTMLElement | null > (null)
const isInitializing = ref(false)
const isScanning = ref(false)
const lastScanTime = ref(0)
let onDetectedHandler = null// 统一停止/清理
const stopScan = () => {try { Quagga.stop() } catch { }const el = interactiveRef.value || (document.querySelector('#interactive') || null)if (el) el.style.display = 'none'if (onDetectedHandler) {Quagga.offDetected(onDetectedHandler)onDetectedHandler = null}isScanning.value = falseisInitializing.value = false
}const handleScan = async () => {// 防抖:1s 内不重复触发const now = Date.now()if (now - lastScanTime.value < 1000) returnlastScanTime.value = now// ✅ 修复:不要写成 if (!isMobile.value); 末尾多分号if (!isMobile.value) {toast('不是手机端登录', 'warning')return}// 避免重复初始化/启动if (isInitializing.value || isScanning.value) {toast('正在打开摄像头…', 'info')return}const container = interactiveRef.value || (document.querySelector('#interactive') | null)if (!container) {toast('找不到扫码容器 #interactive', 'error')return}// 显示并给尺寸(没有尺寸很难识别)container.style.display = 'block'container.style.width = '100%'container.style.height = '60vh'isInitializing.value = truetry {await new Promise((resolve, reject) => {Quagga.init({inputStream: {name: 'Live',type: 'LiveStream',target: container,constraints: {facingMode: 'environment',width: { min: 640 },height: { min: 480 },},},decoder: { readers: ['code_128_reader', 'ean_reader'] },locate: true,},(err) => (err ? reject(err) : resolve()),)})Quagga.start()isScanning.value = truetoast('摄像头已启动', 'success')} catch (e) {console.error('摄像头/初始化失败', e)toast('无法启动摄像头:请使用 HTTPS 并允许相机权限', 'error')stopScan()return} finally {isInitializing.value = false}// 识别一次即关闭(做一次性处理)anyonDetectedHandler = (data) => {if (!isScanning.value) returnconst code = data?.codeResult?.codeif (code) {trackingNumber.value = code // ✅ 把结果写回输入框toast('已识别:' + code, 'success')// todo 在这里添加扫描后需调用的逻辑stopScan()}}Quagga.onDetected(onDetectedHandler)
}// 清理资源
onBeforeUnmount(() => {stopScan()
});</script>

http://www.lryc.cn/news/626601.html

相关文章:

  • 如何将数据从 iPhone 转移到 vivo?
  • 23种设计模式——构建器模式(Builder Pattern)详解
  • Jenkins服务器配置SSH
  • 【Ansible】变量、机密、事实
  • 云计算学习100天-第25天
  • ansible中roles角色是什么意思?
  • 苹果XR芯片介绍
  • 【JavaEE】多线程 -- 定时器
  • GO环境变量中GO111MODULE到底是干啥的?
  • 心路历程-了解网络相关知识
  • 【论文阅读】Multi-metrics adaptively identifies backdoors in Federated Learning
  • Azure 使用记录
  • mapbox高阶,结合threejs(threebox)添加建筑glb模型,添加阴影效果,设置阴影颜色和透明度
  • 通过try-catch判断数据库唯一键字段是否重复
  • linux的内核符号表
  • 【表的操作】
  • 深入理解 Linux 多线程
  • mysql-8.0.37-linux-glibc2.12-x86_64安装
  • 可实现三重空间感知:Ai2 开源具身机器人 AI 模型 MolmoAct
  • 从防抖节流到链表树:编程世界中的抽象优化艺术
  • 23种设计模式——模板方法模式(Template Method Pattern)详解
  • 在一台没联网的机器上,用ollama加载qwen3,14b
  • 遥感机器学习入门实战教程|Sklearn 案例④ :多分类器对比(SVM / RF / kNN / Logistic...)
  • 使用 GraalVM Native Image 将 Spring Boot 应用编译为跨平台原生镜像:完整指南
  • Spring Boot 配置
  • nvidia最新论文:小型语言模型是代理人工智能的未来
  • (5)软件包管理器 yum | Vim 编辑器 | Vim 文本批量化操作 | 配置 Vim
  • 5G-A赋能AR眼镜:毫米级虚实融合的未来已来
  • 开源 AR 眼镜怎么选?OpenGlass ,OSSG,cheApR 分析推荐
  • 给你的Unity编辑器添加实现类似 Odin 的 条件显示字段 (ShowIf/HideIf) 功能