Pinia不监听扫码枪硬件输入,而是管理其输入后的状态:捕获键盘事件→清洗数据→存入Store→跨组件响应;需用聚焦input捕获回车输入,通过receiveInput更新state,$subscribe监听变更触发业务逻辑。

Pinia 本身不直接监听硬件输入(比如扫码枪),但它非常适合管理扫码枪输入后的解析结果、状态流转和跨组件共享逻辑。扫码枪本质是模拟键盘输入(通常以回车结尾),所以核心在于:前端捕获输入事件 → 提取有效数据 → 存入 Pinia Store 统一管理 → 其他组件响应变更。
扫码输入的典型流程与 Pinia 角色定位
扫码枪触发的是 input 或 keydown 事件,不是 Pinia 的职责范围;Pinia 负责的是“输入之后”的状态管理部分:
- 输入框聚焦时才接收扫码内容(避免误触)
- 自动截取扫码字符串(剔除干扰字符、识别分隔符)
- 记录最近一次扫码值、解析状态(成功/失败)、错误原因
- 支持多页面/组件读取当前扫码结果(如订单页查商品、入库页录批次)
- 可配合
$subscribe做扫码埋点或防重复提交
定义扫码 Store:state + 解析逻辑封装
在 src/stores/scan.ts 中定义:
<!-- src/stores/scan.ts -->
import { defineStore } from 'pinia'export const useScanStore = defineStore('scan', { state: () => ({ lastRaw: '', // 原始输入(含换行/制表符等) lastCode: '', // 清洗后条码(如去除末尾 \r\n) isValid: false, // 是否通过基础校验(非空、长度合理) error: '' as string | null, isLoading: false, // 可用于防抖或接口请求中状态 }), getters: { isScanning: (state) => state.lastRaw.length > 0 && !state.isValid, cleanCode: (state) => state.lastCode.trim().replace(/[\r\n\t]/g, '') }, actions: { // 主动注入扫码原始内容(由 input 事件调用) receiveInput(raw: string) { this.lastRaw = raw const cleaned = raw.trim().replace(/[\r\n\t]+$/, '') if (cleaned.length >= 6 && cleaned.length <= 32) { this.lastCode = cleaned this.isValid = true this.error = null } else { this.isValid = false this.error = '条码长度异常' } }, // 手动重置,供扫码成功后清空 reset() { this.lastRaw = '' this.lastCode = '' this.isValid = false this.error = null } })
在组件中绑定扫码输入(聚焦 + 回车触发)
不需要全局监听 keydown;只需让一个隐藏或专用的 <input> 接收焦点,并在回车时把值传给 Store:
<!-- 示例:ScanInput.vue -->
<template> <input ref="inputRef" type="text" class="sr-only" @keydown.enter="onScan" @blur="onBlur" /></template>
<script setup>import { ref, onMounted, onUnmounted } from 'vue'import { useScanStore } from '@/stores/scan'const inputRef = ref<HTMLInputElement | null>(null)const scanStore = useScanStore()const onScan = (e: Event) => { const target = e.target as HTMLInputElement scanStore.receiveInput(target.value) target.value = '' // 清空输入框 inputRef.value?.focus()}const onBlur = () => { // 防止失焦后仍能扫码,可选 inputRef.value?.focus()}onMounted(() => { inputRef.value?.focus()})</script>
监听扫码变更并联动业务($subscribe 或 computed)
其他组件可直接读取 scanStore.lastCode,也可用 $subscribe 实现无侵入式响应:
// 在需要自动处理扫码的页面 setup 中const scanStore = useScanStore()scanStore.$subscribe((mutation, state) => { if (mutation.type === 'direct' && state.isValid && state.lastCode) { console.log('新扫码:', state.lastCode) // 触发查询商品、跳转、弹窗等业务逻辑 fetchProductByCode(state.lastCode) scanStore.reset() // 处理完即重置 }})


















