扫码枪扫码原理
扫码枪会将扫描到的数据代入到获取焦点的输入框中,并且触发输入框的“Enter”事件
1、中文输入法扫码枪扫码会导致很多键位识别为229。导致无法识别设备回车。
2、部分老式扫码枪在中文大写模式下录入完成最后一个键位code不是13(回车),而是20(Caps_Lock, 大小写切换)
扫码功能实现
代码示例是实际项目中使用的扫码枪功能,
router只是用作扫码回调函数的函数名核心是监听
keypress事件有其他实现是使用
keyup或者keydown
import Vue from 'vue'
import router from '@/router/routers'
// 触发器总集合
const SCAN_LISTENER_MANAGER = []
function execFunc(listener, param) {
listener.callback.call(listener.thisArg, param)
}
const scanListener = {
/**
* 添加监听器
* @param {string} name
* @param {Function|*} listener
*/
on(name, listener) {
if (!name || !isNaN(parseInt(name))) { throw TypeError('监听器名称只能为英文字母以及下划线!') }
// 判断当前监听器是否存在,不存在则直接创建一个空数组
if (SCAN_LISTENER_MANAGER[name] === undefined) { SCAN_LISTENER_MANAGER[name] = [] }
if (typeof listener !== 'object') {
listener = { callback: listener }
}
if (typeof listener.callback !== 'function') {
throw TypeError('监听器必须是一个function!')
}
SCAN_LISTENER_MANAGER[name].push(listener)
return listener
},
/**
* 添加监听器 - 只执行一次
* @param {string} name
* @param {Function|*} listener
*/
once(name, listener) {
if (typeof listener !== 'object') {
listener = { callback: listener }
}
listener.once = true
return this.on(name, listener)
},
/**
* 移除监听器
* @param {string} name
* @param {Function} listener
*/
off(name, listener) {
if (!(typeof listener === 'function' || typeof listener === 'object')) return
// 处理器
const handler = (listeners, listener) => {
if (typeof listener === 'object') {
const index = listeners.indexOf(listener)
if (index !== -1) listeners.splice(index, 1)
} else if (typeof listener === 'function') {
for (const i in listeners) {
if (listeners[i].callback == listener) listeners.splice(i, 1)
}
}
}
if (!name || !isNaN(parseInt(name))) {
// 所有监听器都移除这个回调函数
SCAN_LISTENER_MANAGER.forEach(listeners => handler(listeners, listener))
} else {
handler(SCAN_LISTENER_MANAGER[name] || [], listener)
}
},
/**
* 移除监听器, 移除指定事件名称下的所有回调方法
* @param {string} name
*/
offAll(name) {
name &&
SCAN_LISTENER_MANAGER[name] &&
!SCAN_LISTENER_MANAGER[name].length &&
(SCAN_LISTENER_MANAGER[name] = [])
},
/**
* 触发监听器
* @param {string} name
* @param {*} [param]
*/
emit(name, param) {
if (!name || !isNaN(parseInt(name))) { throw TypeError('监听器名称只能为英文字母以及下划线!') }
const listeners = SCAN_LISTENER_MANAGER[name] || []
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
if (listener.once) {
listeners.splice(i, 1)
i--
}
execFunc(listener, param)
}
}
}
const scanMixin = {
/* beforeDestroy() {
// 当前组件销毁时,也移除扫码事件
scanListener.offAll(router.currentRoute.path)
},*/
methods: {
// 移除扫码事件方法
$offScanEvent(listener) {
scanListener.off(this.$route.path, listener)
},
// 监听扫码事件
$onScanEvent(listener) {
const path = this.$route.path
const _listener = scanListener.on(path, listener)
this.$once('hook:beforeDestroy', function() {
scanListener.off(path, _listener)
})
}
}
}
// 扫码监听器全局混入
Vue.mixin(scanMixin)
核心
/*
* 监听整个文档的keypress事件,识别键盘输入和扫码枪输入
* 扫码枪输入在回车符号后,向当前路由名称emit事件
* */
let lastTimeStamp = null // 上一次记录的时间戳
let codeString = '' // 记录内容
let isScanInput = false // 是否处在扫码枪模式
document.addEventListener('keypress', function(e) {
const timeStamp = e.timeStamp
// 第一次记录字符
if (lastTimeStamp == null) {
lastTimeStamp = timeStamp
}
const diffTime = timeStamp - lastTimeStamp // 时间间隔
const isNormalDiffTime = diffTime < 50 // 是否在 正常的扫码枪输入的时间间隔 范围之内
// 是否 进入扫码模式 且在允许的时间间隔 范围之内
const isScanDiffTime = isScanInput && !isNormalDiffTime && diffTime < 1000
// 距上次记录间隔小于指定时间,或者 如果是扫码枪模式,允许一次较大时间
if (isNormalDiffTime || isScanDiffTime) {
if (isScanDiffTime) {
isScanInput = false
}
// 如果是回车
if (e.keyCode == '13') {
// 有内容,则发送事件, 没有则跳出
if (!codeString) return
// 提取出记录到的内容
const Result = codeString
codeString = ''
// 触发事件
setTimeout(function() {
scanListener.emit(router.currentRoute.path, Result)
}, 0)
} else {
// 小于100ms认为接下来是扫码枪模式
if (isNormalDiffTime) isScanInput = true
// 则堆加入内容
codeString += String.fromCharCode(e.keyCode)
}
} else {
isScanInput = false
if (e.keyCode != '13') codeString = String.fromCharCode(e.keyCode)
}
// 记录当前输入的时间
lastTimeStamp = timeStamp
})
使用
mounted() {
this.$onScanEvent(this.scanCode)
},
methods: {
scanCode(code) {
console.log('扫码结果:', code)
}
}