js如何实现扫描枪快速扫码录入的功能

目录
文章目录隐藏
  1. 实践背景
  2. 需要解决的问题
  3. 代码实现
  4. 最终代码
  5. 结语

js 如何实现扫描枪快速扫码录入的功能

js 如何实现扫描枪快速扫码录入的功能(区分手动输入和扫码枪录入)。

实践背景

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

  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() {}
    }
}

2. 事件注册在那里,注册什么事件,用什么方式注册

  • 因为我们要在页面任意位置识别并聚焦到固定的input中,所以我们需要把事件放到document上面。
  • 因为keydown事件按下不抬起会一直触发,所以这里我们采用keyup事件更加友好。
  • 我们这里使用了addEventListener注册事件,removeEventListener来删除事件。这两个方法有三个参数,分别为(“事件名”,“事件触发的函数”,“采用捕获还是冒泡”)。这里我就不做赘述了,详细说明查看下面文档:官方文档

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

methods:{
    // 添加事件
    addKeyUp(){
	document.addEventListener("keyup",this.documentKeyUp,true)
    },
    // 删除事件
    removeKeyUp(){
        document.removeEventListener("keyup",this.documentKeyUp,true)
    }
}

3.如何不影响页面上其他 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
    }
}

4. 如何区分手动输入和扫码枪录入(最为关键的部分)

问题分析:

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

结语

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

「点点赞赏,手留余香」

4

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
码云笔记 » js如何实现扫描枪快速扫码录入的功能

发表回复