js通过扫描枪快速扫码录入的功能实现(区分手动输入和扫码枪录入)-pc

实践背景

在近期工作过程中接手了一个让我有些棘手的需求,需求如下:

  1. 输入框内支持扫码录入商品,且支持连续扫码录入。
  2. 相同输入框中支持手动输入条码录入商品。
  3. 页面任意位置用扫码枪扫码都可以成功定位到该输入框且录入对应商品。

需要解决的问题

  1. 事件注册在那里
  2. 事件注册什么时候注册,什么时候注销。
  3. 如何不影响页面上其他input元素
  4. 如何区分手动输入和扫码枪录入

代码实现

  1. 事件注册什么时候注册,什么时候注销
    因为我们要注册的为全局事件,但是又不能影响到其他页面所以我们可以借助vue的生命周期来注册卸载。楼主这里因为页面切换用的是keeplive所以我是将事件注册放到了 created() 和 activated()中
	// 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(){}
	    }
	}
	
  1. 事件注册在那里,注册什么事件,用什么方式注册
    (1) 因为我们要在页面任意位置识别并聚焦到固定的input中,所以我们需要把事件放到document上面
    (2) 因为keydown事件按下不抬起会一直触发,所以这里我们采用keyup事件更加友好。
    (3) 我们这里使用了addEventListener注册事件,removeEventListener来删除事件。这两个方法有三个参数,分别为 (“事件名”,“事件触发的函数”,“采用捕获还是冒泡”) 。这里我就不做赘述了,详细说明查看下面文档:官方文档 或者 相关博客例如:https://blog.csdn.net/l908825925/article/details/107865676

PS: 此处需注意一个细节,添加事件和删除事件的所有参数必须一致,否则会导致无法删除

	methods:{
        // 添加事件
    	addKeyUp(){
	       	document.addEventListener("keyup",this.documentKeyUp,true)
        }
    	// 删除事件
        removeKeyUp(){
        	document.removeEventListener("keyup",this.documentKeyUp,true)
        }
    }
  1. 如何不影响页面上其他input元素
    因为我们将事件注册到了document所以我们的keyup事件必然会影响到输入,我们要避免中情况我们就需要禁止页面上所有的事件冒泡,导致执行document上的keyup事件触发。那么我们怎么去判断呢,我这边采用的分析event数据中的event.srcElement.tagName来进行判断。每一个元素的tagName都不一样所以我们只需要判断我们keyup时的event.srcElement.tagName是否等于 “INPUT” || "TEXTAREA "
	methods:{
    	documentKeyUp(event){
	       	if(["INPUT","TEXTAREA"].includes(event.srcElement.tagName)) return
        }
    }
  1. 如何区分手动输入和扫码枪录入 (最为关键的部分)

问题分析:
这个问题我们需要从硬件去分析,首先,扫码抢输入特点为快速录入自动在输入结束触发回车,人为按键输入相对扫码枪输入较慢,手动触发回车事件。那么我们从哪儿来拿到这个时间呢,通过分析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, 大小写切换)

结语

该文章是为个人的思路及实现的实践总结,代码并不严谨优雅,希望对各位开发者有所启发,若有不足还望多多指教。

  • 8
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Vue 是一个用于构建用户界面的渐进式 JavaScript 框架,Vue 扫码能够实现无焦点捕获扫码输入扫码是一种硬件设备,它能够将二维码或条形码的信息转化为可识别的数据。传统上,为了使用扫码,用户需要将光标聚焦于输入框中,然后才能够将扫码对准二维码或条形码进行扫描。然而,使用 Vue 扫码插件,我们能够实现无焦点捕获扫码输入功能。 通过在 Vue 组件中使用合适的库或插件,我们可以实现这一功能。这样做的原理是将扫码的扫描结果直接传递给指定输入框,而不需要用户手动聚焦于输入框中。 在 Vue 的生命周期钩子中,我们可以监听扫码设备的事件,如 "scan"。当扫码扫描到二维码或条形码时,将触发这个事件。我们可以在这个事件中通过 JavaScript 来处理扫描结果,然后将其赋值给指定的输入框。 同时,我们可以借助 Vue 的双向数据绑定功能实现扫码扫描结果的值动态更新到其他需要使用这个值的地方。 需要注意的是,为了确保无焦点捕获扫码输入功能正常工作,我们需要在 Vue 组件中的对应输入框上添加适当的事件监听器,以便识别到扫码输入。 总的来说,通过使用 Vue 扫码插件和相关的库或插件,我们可以实现无焦点捕获扫码输入功能,提高用户的扫码体验和输入效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白开水丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值