如何在React PWA中实现RFID标签的读写及读卡器监听功能
React PWA 实现RFID读卡器监听与标签读写方案
第一步:确认读卡器兼容的Web API
首先根据你手上读卡器的类型选择对应的实现路径:
- 如果是高频NFC类RFID读卡器/标签:优先用Web NFC API,属于W3C标准,PWA在HTTPS环境/localhost下可直接调用,安卓端Chrome 89+原生支持,桌面端多数主流浏览器已适配。
- 如果是USB接口的自定义协议RFID读卡器:走Web USB API,需要用户主动授权设备访问权限,同样要求HTTPS/localhost运行环境。
- 如果是普通模拟键盘输出的免驱RFID读卡器:不需要调用特殊API,直接监听全局键盘输入事件即可,这类读卡器读到标签后会自动把卡号按字符依次输出,默认末尾带回车换行符。
第二步:对应场景的实现代码
场景1:模拟键盘输入型读卡器(兼容性最高,无需额外权限)
import { useEffect, useState } from 'react'; function RfidReader() { const [rfidCardNo, setRfidCardNo] = useState(''); let inputBuffer = []; // 读卡器输入间隔远小于人工输入,100ms超时即可判断一次输入结束 const INPUT_TIMEOUT = 100; let inputTimer = null; useEffect(() => { const handleKeyDown = (e) => { // 过滤功能键,仅保留可打印字符 if (e.key.length === 1) { clearTimeout(inputTimer); inputBuffer.push(e.key); inputTimer = setTimeout(() => { // 可根据你实际使用的卡片长度调整判断阈值 if (inputBuffer.length >= 8 && inputBuffer.length <= 16) { const cardNo = inputBuffer.join(''); setRfidCardNo(cardNo); // 此处可添加拿到卡号后的业务逻辑 } inputBuffer = []; }, INPUT_TIMEOUT); } // 也可监听读卡器默认输出的回车作为输入结束标志 if (e.key === 'Enter') { clearTimeout(inputTimer); if (inputBuffer.length) { const cardNo = inputBuffer.join(''); setRfidCardNo(cardNo); inputBuffer = []; } } }; window.addEventListener('keydown', handleKeyDown); return () => { window.removeEventListener('keydown', handleKeyDown); clearTimeout(inputTimer); }; }, []); return <div>当前读到的卡号:{rfidCardNo || '未检测到卡片'}</div>; } export default RfidReader;
场景2:NFC类型RFID(Web NFC API实现,支持读写)
import { useEffect, useState } from 'react'; function NfcRfidReader() { const [tagData, setTagData] = useState(null); const [writeStatus, setWriteStatus] = useState(''); useEffect(() => { if (!('NDEFReader' in window)) { console.log('当前浏览器不支持Web NFC'); return; } const ndef = new NDEFReader(); ndef.scan().then(() => { ndef.onreading = (event) => { const records = event.message.records; const decoder = new TextDecoder('utf-8'); const data = decoder.decode(records[0].data); setTagData({ serialNumber: event.serialNumber, content: data }); }; ndef.onreadingerror = () => console.log('读取标签失败'); }).catch(err => console.log('启动NFC扫描失败:', err)); // 标签写入方法 window.writeNfcTag = async (content) => { try { await ndef.write({ records: [{ recordType: 'text', data: content, lang: 'zh' }] }); setWriteStatus('写入成功'); } catch (err) { setWriteStatus(`写入失败:${err.message}`); } }; }, []); return ( <div> <div>当前标签信息:{tagData ? `卡号:${tagData.serialNumber},内容:${tagData.content}` : '未检测到NFC标签'}</div> <button onClick={() => window.writeNfcTag('自定义写入内容')}>写入测试内容</button> <div>写入状态:{writeStatus}</div> </div> ); } export default NfcRfidReader;
场景3:自定义USB协议RFID读卡器(Web USB API实现)
需提前拿到读卡器的USB VID(厂商ID)、PID(产品ID)、通信协议、输入端点号等参数,替换到对应位置即可:
import { useEffect, useState } from 'react'; function UsbRfidReader() { const [device, setDevice] = useState(null); const [cardNo, setCardNo] = useState(''); // 替换为你的读卡器实际VID、PID const READER_VID = 0x1234; const READER_PID = 0x5678; // 替换为你的读卡器实际输入端点号 const INPUT_ENDPOINT = 0x81; const requestDevice = async () => { try { const usbDevice = await navigator.usb.requestDevice({ filters: [{ vendorId: READER_VID, productId: READER_PID }] }); await usbDevice.open(); await usbDevice.selectConfiguration(1); await usbDevice.claimInterface(0); setDevice(usbDevice); startListening(usbDevice); } catch (err) { console.log('连接读卡器失败:', err); } }; const startListening = async (usbDevice) => { while (usbDevice.opened) { try { const result = await usbDevice.transferIn(INPUT_ENDPOINT, 64); const decoder = new TextDecoder(); const rawData = decoder.decode(result.data).trim(); // 此处按读卡器通信协议解析rawData得到卡号 if (rawData) { setCardNo(rawData); } } catch (err) { console.log('读取数据失败:', err); break; } } }; useEffect(() => { if (!('usb' in navigator)) { console.log('当前浏览器不支持Web USB'); return; } // 页面加载时自动匹配已授权的读卡器 navigator.usb.getDevices().then(devices => { const targetDevice = devices.find(d => d.vendorId === READER_VID && d.productId === READER_PID); if (targetDevice) { setDevice(targetDevice); startListening(targetDevice); } }); }, []); return ( <div> {!device && <button onClick={requestDevice}>连接RFID读卡器</button>} <div>当前读到的卡号:{cardNo || '未检测到卡片'}</div> </div> ); } export default UsbRfidReader;
第三步:PWA适配注意点
- 所有Web API都要求应用运行在HTTPS环境或者localhost下,部署时需满足该要求。
- 离线使用场景下,将相关页面和JS资源添加到PWA的Service Worker缓存清单即可。
- Web NFC、Web USB的用户授权会长期保留,后续打开应用无需重复授权。
- iOS端适配注意:目前iOS Safari仅支持读取NDEF格式的NFC标签,不支持写入,也不支持Web USB,优先选择模拟键盘输入型读卡器可获得最高兼容性。
内容的提问来源于stack exchange,提问作者Artist
相关产品推荐
相关产品推荐

