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

如何在vue3+ts项目中实现zebra扫描枪扫码效果

1实现一个hooks

import { onMounted, onUnmounted, ref } from 'vue' interface ScanOptions { threshold?: number minLength?: number onScanProgress?: (buffer: string) => void onScanSuccess: (code: string) => void } export function useScanGun(options: ScanOptions) { const { threshold = 100, minLength = 6, onScanProgress, onScanSuccess } = options const codeBuffer = ref('') const lastScanned = ref('') let lastTime = 0 let timer: ReturnType<typeof setTimeout> | null = null const commit = (preventDefaultEvent?: KeyboardEvent) => { const value = codeBuffer.value if (value.length >= minLength) { lastScanned.value = value onScanSuccess(value) if (preventDefaultEvent) preventDefaultEvent.preventDefault() } codeBuffer.value = '' lastTime = 0 } const handleKeyDown = (event: KeyboardEvent) => { const currentTime = Date.now() if (timer !== null) { clearTimeout(timer) timer = null } if (event.metaKey || event.ctrlKey || event.altKey) return const limit = event.key === 'Enter' ? threshold * 2 : threshold if (lastTime !== 0 && currentTime - lastTime > limit) { codeBuffer.value = '' } if (event.key === 'Enter') { commit(event) return } if (event.key.length === 1) { codeBuffer.value += event.key onScanProgress?.(codeBuffer.value) } lastTime = currentTime timer = setTimeout(() => { commit() }, threshold * 2) } onMounted(() => { window.addEventListener('keydown', handleKeyDown, true) }) onUnmounted(() => { if (timer !== null) { clearTimeout(timer) timer = null } window.removeEventListener('keydown', handleKeyDown, true) }) return { codeBuffer, lastScanned } }

2 在app.vue中全局监听扫码的结果

<script setup lang="ts"> import zhCn from 'element-plus/es/locale/lang/zh-cn' import { onMounted, ref } from 'vue' import { recordProgress, signRegister } from '@/apis' import { useScanGun } from '@/hooks/useScan' const SCANNER_PREFIXES = ['A|', 'B|', 'C|', 'D|', 'E|', 'F|'] as const type ScannerPrefix = (typeof SCANNER_PREFIXES)[number] const parseScannerPayload = (raw: string): { prefix: ScannerPrefix; payload: string } | null => { const text = String(raw ?? '').trim() if (!text) return null for (const prefix of SCANNER_PREFIXES) { if (text.startsWith(prefix)) return { prefix, payload: text.slice(prefix.length) } } return null } const code = ref('') useScanGun({ threshold: 200, onScanProgress: (buffer) => { console.log('codeBuffer', buffer) }, onScanSuccess: (result) => { console.log('app---扫码成功:', result) const parsed = parseScannerPayload(result) const rawPayload = (parsed?.payload ?? result).trim() if (!rawPayload) return const rawParts = rawPayload.split('-') const orderNo = rawParts[0]?.trim() || '' const cardNo = rawParts.length >= 2 ? rawParts.slice(1).join('-').trim() : '' const inputValue = cardNo || rawPayload code.value = inputValue window.dispatchEvent( new CustomEvent('global-scan', { detail: { raw: result, prefix: parsed?.prefix, rawPayload, orderNo, cardNo, payload: inputValue } }) ) const active = document.activeElement if (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement) { active.value = inputValue active.dispatchEvent(new Event('input', { bubbles: true })) } //工位一:扫码只得到客户邮寄的订单信息 if (parsed?.prefix === 'A|') { signRegister({ logisticsNo: orderNo || rawPayload }) .then((res) => console.log('signRegister success:', res)) .catch((err) => console.error('signRegister error:', err)) return } //其他工位单独区分... if (parsed) { recordProgress({ orderNo: orderNo || rawPayload, cardNos: cardNo ? [cardNo] : [] }) .then((res) => console.log('recordProgress success:', res)) .catch((err) => console.error('recordProgress error:', err)) } } }) onMounted(() => { console.log('扫码枪已就绪') }) </script> <template> <el-config-provider :locale="zhCn"> <router-view></router-view> </el-config-provider> </template> <style scoped></style>

注意,这里 const SCANNER_PREFIXES = ['A|', 'B|', 'C|', 'D|', 'E|', 'F|'] as const的目的是为了区分不同的扫描枪。扫描枪扫码以后得到的数据前会出现A|xxxx,B|xxxxx等。这是通过scan123这个软件设置的。比如扫描枪一设置返回的数据前缀为A|,那么扫描枪1最后通过扫码的结果就是A|XXX,,扫描枪二同理...这时我们在代码里就可以区分不同的扫描枪。让他们去做不同的业务逻辑

const active = document.activeElement if (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement) { active.value = inputValue active.dispatchEvent(new Event('input', { bubbles: true })) }

这里的代码是当用户关闭定位在输入框时,可以自动填充扫码枪的结果

http://www.jsqmd.com/news/339974/

相关文章:

  • 【python 列表(list)和元组(tuple)】创建、访问、基本操作及各自的特点
  • 2026年知名的彩色纸箱印刷厂家口碑推荐汇总 - 行业平台推荐
  • 告别建站难 + 访问限!Halo+cpolar 让个人博客从局域网飞向全网
  • 贪心算法-递增的三页子序列
  • 【微实验】Zhang-Suen 快速并行细化算法与MATLAB实现
  • ESP32-S3入门教程:配置芯片
  • 转行网络安全,学历到底重不重要?
  • 龙魂模型这模型会说谎吗?
  • ESP32-S3入门教程:#include无法找到的解决方案
  • 2025年程序员都转行,我该何去何从呢!
  • 2026年比较好的印刷/彩盒印刷优质厂家推荐汇总 - 行业平台推荐
  • 机器学习入门(二十)支持向量机SVM
  • 2026年河南复合肥优质厂家盘点与采购参考 - 2026年企业推荐榜
  • 2026年口碑好的白酒包装人气实力厂商推荐 - 行业平台推荐
  • 基于动态规划算法的混合动力汽车能量管理建模与计算
  • 深圳跨境电商中的“亚马逊精品模式“详解
  • Phlux Technology 荣获 SPIE 棱镜奖
  • 原子层加工技术推动碳化硅量子光子电路发展
  • 英国团队展示砷化镓量子点发光波长的可调谐对准
  • 2026年靠谱的氟橡胶密封圈厂家口碑排行 - 行业平台推荐
  • 2026年比较好的非标O型圈厂家选购参考汇总 - 行业平台推荐
  • 2026年2月杭州青少年男款内衣实力工厂深度盘点 - 2026年企业推荐榜
  • 2026年防水涂料品牌可靠性深度评估与厂商精选 - 2026年企业推荐榜
  • 2026年评价高的硅胶密封圈/丁腈橡胶密封圈厂家真实测评 - 行业平台推荐
  • ESP32-S2-MINI-2:高性能、高集成度的物联网Wi-Fi模组解析
  • 2026年花生选种指南:头部服务商综合评测与推荐 - 2026年企业推荐榜
  • 现代数据架构的AI驱动转型:AI应用架构师的角色与挑战
  • 家长必看:小学英语服务商挑选标准 - 2026年企业推荐榜
  • 2026年杭州内裤生产厂商技术实力与创新应用评析 - 2026年企业推荐榜
  • 小公司的研发后期,基本等同于售后服务部