在近期工作过程中接手了一个让我有些棘手的需求,需求如下:
// tips:因为f5刷新不会触发activated() 所以我再created中做了创建,但是普通加载又会触发所以有了如下逻辑处理
export default {
data() {
return { isCreate: false }
},
created() {
this.isCreate = true
this.addKeyUp()
},
activated() {
if (!this.isCreate)this.addKeyUp()
},
destroyed(){
this.removeKeyUp()
},
deactivated() {
this.removeKeyUp()
this.isCreate = false
},
methods:{
// 添加事件
addKeyUp(){},
// 删除事件
removeKeyUp(){}
}
}
PS: 此处需注意一个细节,添加事件和删除事件的所有参数必须一致,否则会导致无法删除
methods:{
// 添加事件
addKeyUp(){
document.addEventListener("keyup",this.documentKeyUp,true)
}
// 删除事件
removeKeyUp(){
document.removeEventListener("keyup",this.documentKeyUp,true)
}
}
methods:{
documentKeyUp(event){
if(["INPUT","TEXTAREA"].includes(event.srcElement.tagName)) return
}
}
问题分析:
这个问题我们需要从硬件去分析,首先,扫码抢输入特点为快速录入自动在输入结束触发回车,人为按键输入相对扫码枪输入较慢,手动触发回车事件。那么我们从哪儿来拿到这个时间呢,通过分析event得出timeStamp字段,返回事件发生时的时间戳,扫码枪每次录入是8-10毫秒,手动录入为则在80-120毫秒左右,好一点的设备也会有在30毫秒左右,那么我们就可以用这个时间差来做区分手动录入和扫码枪录入。
所以代码逻辑如下:
export default {
data() {
return {
// 存放每次keyup事件时间戳
keyUpIntervalArray: [],
// 储存每一次按键的内容当让输入框组件获取焦点时拿到内容直接录入商品
scanText:""
}
},
methods:{
documentKeyUp(event){
// event.key.length>1
if(["TEXTAREA","INPUT"].includes(event.srcElement.tagName) || event.key.length>1) return this.scanText = ""
let temp = this.keyUpIntervalArray
// 校验输入
let pattern = /\d|\s|[a-zA-Z]/
if(pattern.test(event.key))this.scanText += event.key
// 只存少量时间戳
temp = util.clone(temp.splice(temp.length-5,5))
temp.push(event.timeStamp)
this.keyUpIntervalArray = temp
// 当储存的小于按键事件时间戳小于2无法对比,则不做判断
if(temp.length<2) return
for(let i in temp){
let num = Math.ceil(temp[temp.length-1]) - Math.ceil(temp[temp.length-2])
if(num < 20 && num !=0){
this.$refs['selectGoods']?.focus(this.scanText)
}
}
}
}
}
input 组件模块
<el-input ref="selectGoods" v-model="searchText" @focus="selectFocus()" @keyup="keyUpEvent" />
// input组件代码
export default {
data() {
return {
// 存放每次keyup事件时间戳
keyUpIntervalArray: [],
// 储存每一次按键的内容当让输入框组件获取焦点时拿到内容直接录入商品
scanText:""
// 是否为扫码录入
scangGun:false
}
},
methods:{
// input 函数
selectFocus(){ this.$refs["selectGoods"].select() },
// input 函数
keyUpEvent(){
if(event?.keyCode === 13 && this.searchText) this.inputGetData(this.scangGun?"":"handle")
this.keyUpIntervalArray = util.clone(this.keyUpIntervalArray.splice(this.keyUpIntervalArray.length-5,5))
this.keyUpIntervalArray.push(event.timeStamp)
if(this.keyUpIntervalArray.length<2) return
for(let i in this.keyUpIntervalArray){
let num = Math.ceil(this.keyUpIntervalArray[this.keyUpIntervalArray.length-1]) - Math.ceil(this.keyUpIntervalArray[this.keyUpIntervalArray.length-2])
this.scangGun = num < 20 && num !=0 ? true : false
if(i>0&&this.keyUpIntervalArray.length === parseInt(i)+1){
if(this.scangGun) return
}
}
}
}
}
document相关处理
export default {
data() {
return {
// 存放每次keyup事件时间戳
keyUpIntervalArray: [],
// 储存每一次按键的内容当让输入框组件获取焦点时拿到内容直接录入商品
scanText:"",
// 是否通过create生命周期
isCreate: false
}
},
created() {
this.isCreate = true
this.addKeyUp()
},
activated() {
if (!this.isCreate) this.addKeyUp()
},
destroyed(){
this.removeKeyUp()
},
deactivated() {
this.removeKeyUp()
this.isCreate = false
},
methods:{
// 添加事件
addKeyUp(){
document.addEventListener("keyup",this.documentKeyUp,true)
},
// 删除事件
removeKeyUp(){
document.removeEventListener("keyup",this.documentKeyUp,true)
},
// document事件处理
documentKeyUp(event){
// event.key.length>1
if(["TEXTAREA","INPUT"].includes(event.srcElement.tagName) || event.key.length>1) return this.scanText = ""
let temp = this.keyUpIntervalArray
// 校验输入
let pattern = /\d|\s|[a-zA-Z]/
if(pattern.test(event.key))this.scanText += event.key
// 只存少量时间戳
temp = util.clone(temp.splice(temp.length-5,5))
temp.push(event.timeStamp)
this.keyUpIntervalArray = temp
// 当储存的小于按键事件时间戳小于2无法对比,则不做判断
if(temp.length<2) return
for(let i in temp){
let num = Math.ceil(temp[temp.length-1]) - Math.ceil(temp[temp.length-2])
if(num < 20 && num !=0) this.$refs['selectGoods']?.focus(this.scanText)
}
}
}
}
PS: 补充内容:
1、中文输入法扫码枪扫码会导致很多键位识别为229。导致无法识别设备回车。
2、部分老式扫码枪在中文大写模式下录入完成最后一个键位code不是13(回车),而是20(Caps_Lock, 大小写切换)
该文章是为个人的思路及实现的实践总结,代码并不严谨优雅,希望对各位开发者有所启发,若有不足还望多多指教。