news 2026/4/23 16:12:25

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何在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 })) }

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 12:51:26

Java套接字编程:深入解析多线程回显服务器的实现

文章目录Java套接字编程&#xff1a;深入解析多线程回显服务器的实现什么是回显服务器&#xff1f;Java套接字编程的基本概念实现一个单线程回显服务器服务端代码实现客户端代码实现运行效果为什么需要多线程&#xff1f;实现一个多线程回显服务器改进后的服务端代码客户端代码…

作者头像 李华
网站建设 2026/4/22 18:46:25

现代数据架构的AI驱动转型:AI应用架构师的角色与挑战

现代数据架构的AI驱动转型&#xff1a;AI应用架构师的角色与挑战 一、引言&#xff1a;为什么AI驱动的数据架构转型是必然&#xff1f; 1.1 传统数据架构的“失效”困境 在数字化浪潮下&#xff0c;企业的数据环境正在发生根本性变化&#xff1a; 数据量爆炸&#xff1a;IDC预测…

作者头像 李华
网站建设 2026/4/23 8:42:53

使用GD32F103C8T6开发板的标准库实现硬件I2C协议通信(附源码下载地址)

代码说明&#xff1a; 该I2C驱动实现了完整的硬件I2C配置&#xff0c;包括GPIO引脚设置、时钟配置和模式配置包含全面的异常处理机制&#xff0c;能够检测和处理超时、NACK、总线忙、仲裁丢失等异常情况提供了多种I2C操作函数&#xff0c;包括单字节读写和多字节读写操作实现了…

作者头像 李华
网站建设 2026/4/23 8:41:00

短剧收稿编辑的福音:2026年AI 评剧本让优质剧本脱颖而出

做短剧剧本收稿编辑五年&#xff0c;我见证了短剧行业从野蛮生长到规范化发展的全过程。但随之而来的&#xff0c;是越来越繁重的审稿压力 ——短剧投稿量翻倍增长&#xff0c;优质剧本却依旧稀缺&#xff0c;每天在海量同质化剧本中 “大海捞针”&#xff0c;还要和编剧反复沟…

作者头像 李华
网站建设 2026/4/23 8:41:04

软件库APP开源Flutter SoftLib源码 带后端源码

本项目为开源学习项目。 &#x1f393; 学习用途&#xff1a;本项目旨在展示Flutter开发技术和最佳实践&#x1f6ab; 禁止非法使用&#xff1a;严禁将本项目用于任何非法活动&#x1f4dd; 免责声明&#xff1a;开发者不对使用本项目造成的任何后果承担责任&#x1f512; 合规…

作者头像 李华
网站建设 2026/4/23 8:42:53

金蝶云星空与Clover POS系统数据互通对接

金蝶云星空与Clover POS系统的对接&#xff0c;核心是通过小懿互联集成平台实现双方核心数据的无缝互通&#xff0c;打通基础资料&#xff08;物料、仓库、客户&#xff09;、业务单据&#xff08;销售出库单与收银订单&#xff09;及库存数据的精准同步&#xff0c;依托小懿互…

作者头像 李华