新文章 网摘 文章 随笔 日记

国外牛人写的检测条码枪输入的js

/*
 * onScan.js - scan-events for hardware barcodes scanners in javascript
 */
var onScan = {        
    attachTo: function(oDomElement, oOptions) {

        if(oDomElement.scannerDetectionData != undefined){
            throw new Error("onScan.js is already initialized for DOM element " + oDomElement);
        }

        var oDefaults = {
            onScan: function(sScanned, iQty){}, // Callback after detection of a successfull scanning:  function(){sScancode, iCount)}()
            onScanError: function(oDebug){}, // Callback after detection of a unsuccessfull scanning (scanned string in parameter)
            onKeyProcess: function(sChar, oEvent){}, // Callback after receiving and processing a char (scanned char in parameter)
            onKeyDetect: function(iKeyCode, oEvent){}, // Callback after detecting a keyDown (key char in parameter) - in contrast to onKeyProcess, this fires for non-character keys like tab, arrows, etc. too!
            onPaste: function(sPasted, oEvent){}, // Callback after receiving a value on paste, no matter if it is a valid code or not
            keyCodeMapper: function(oEvent){return String.fromCharCode(oEvent.which)}, // Custom function to decode a keydown event into a character. Must return decoded character or NULL if the given event should not be processed.
            onScanButtonLongPress: function(){}, // Callback after detection of a successfull scan while the scan button was pressed and held down
            scanButtonKeyCode:false, // Key code of the scanner hardware button (if the scanner button a acts as a key itself) 
            scanButtonLongPressTime:500, // How long (ms) the hardware button should be pressed, until a callback gets executed
            timeBeforeScanTest:100, // Wait duration (ms) after keypress event to check if scanning is finished
            avgTimeByChar:30, // Average time (ms) between 2 chars. Used to do difference between keyboard typing and scanning
            minLength:6, // Minimum length for a scanning
            suffixKeyCodes:[9,13], // Chars to remove and means end of scanning
            prefixKeyCodes:[], // Chars to remove and means start of scanning
            ignoreIfFocusOn:false, // do not handle scans if the currently focused element matches this selector or object
            stopPropagation:false, // Stop immediate propagation on keypress event
            preventDefault:false, // Prevent default action on keypress event
            reactToKeydown:true, // look for scan input in keyboard events
            reactToPaste:false, // look for scan input in paste events
            singleScanQty: 1 // Quantity of Items put out to onScan in a single scan
        }
                                
        oOptions = this._mergeOptions(oDefaults, oOptions);

        // initializing options and variables on DomElement
        oDomElement.scannerDetectionData = {
                options: oOptions,
                vars:{
                    firstCharTime: 0,
                    lastCharTime: 0,
                    stringWriting: '',
                    callIsScanner: false,
                    testTimer: false,
                    longPressTimeStart: 0,
                    longPressed: false
                }
            
        };
        
        // initializing handlers (based on settings)
        if (oOptions.reactToPaste === true){
            oDomElement.addEventListener("paste", this._handlePaste);
        }
        if (oOptions.scanButtonKeyCode !== false){
            oDomElement.addEventListener("keyup", this._handleKeyUp);
        }
        if (oOptions.reactToKeydown === true || oOptions.scanButtonKeyCode !== false){    
            oDomElement.addEventListener("keydown", this._handleKeyDown);
        }
    },
    
    detachFrom: function(oDomElement) {
        // detaching all used events
        if (oDomElement.scannerDetectionData.options.reactToPaste){
            oDomElement.removeEventListener("paste", this._handlePaste);
        }
        if (oDomElement.scannerDetectionData.options.scanButtonKeyCode !== false){
            oDomElement.removeEventListener("keyup", this._handleKeyUp);
        }
        oDomElement.removeEventListener("keydown", this._handleKeyDown);
        
        // clearing data off DomElement
        oDomElement.scannerDetectionData = undefined; 
        
    },
    
    getOptions: function(oDomElement){
        return oDomElement.scannerDetectionData.options;            
    },
    
    setOptions: function(oDomElement, oOptions){
        // check if some handlers need to be changed based on possible option changes
        switch (oDomElement.scannerDetectionData.options.reactToPaste){
            case true: 
                if (oOptions.reactToPaste === false){
                    oDomElement.removeEventListener("paste", this._handlePaste);
                }
                break;
            case false:
                if (oOptions.reactToPaste === true){
                    oDomElement.addEventListener("paste", this._handlePaste);
                }
                break;
        }
        
        switch (oDomElement.scannerDetectionData.options.scanButtonKeyCode){
            case false:
                if (oOptions.scanButtonKeyCode !== false){
                    oDomElement.addEventListener("keyup", this._handleKeyUp);
                }
                break;
            default: 
                if (oOptions.scanButtonKeyCode === false){
                    oDomElement.removeEventListener("keyup", this._handleKeyUp);
                }
                break;
        }
        
        // merge old and new options
        oDomElement.scannerDetectionData.options = this._mergeOptions(oDomElement.scannerDetectionData.options, oOptions);
    
        // reinitiallize
        this._reinitialize(oDomElement);
    },
    
        
    simulate: function(oDomElement, sTestString){
        var oVars = oDomElement['scannerDetectionData'].vars;
        oVars.firstCharTime = 0;
        oVars.lastCharTime = 0;
        oVars.stringWriting = sTestString;
        this._validateScanCode(oDomElement);
        return this;
    },
    
    _reinitialize: function(oDomElement){
        var oVars = oDomElement['scannerDetectionData'].vars;
        oVars.firstCharTime = 0;
        oVars.stringWriting = '';

    },
    
    _isFocusOnIgnoredElement: function(oDomElement){
        
        oIgnoredObject = oDomElement['scannerDetectionData'].options.ignoreIfFocusOn;

        if(!oIgnoredObject){
            return false;
        }
    
        var oFocused = document.activeElement;
        
        // checks if ignored element is an array, and if so it checks if one of the elements of it is an active one
        if (Array.isArray(oIgnoredObject)){
            for(var i=0; i<oIgnoredObject.length; i++){
                if(Object.is(oFocused, oIgnoredObject[i]) || Object.is(oFocused, document.getElementById(oIgnoredObject[i]))){
                    return true;
                }
            }
        // if the option consists of an single element, it only checks this one
        } else if (Object.is(oFocused, oIgnoredObject) || Object.is(oFocused, document.getElementById(oIgnoredObject))){
            return true;                    
        }
        
        // if the active element is not listed in the ignoreIfFocusOn option, return false
        return false;
    },
    
    _validateScanCode: function(oDomElement){
        var oScannerData = oDomElement['scannerDetectionData'];            
        var oOptions = oScannerData.options;
        var iSingleScanQty = oScannerData.options.singleScanQty
        var sScanCode = oScannerData.vars.stringWriting;
        var iFirstCharTime = oScannerData.vars.firstCharTime;
        var iLastCharTime = oScannerData.vars.lastCharTime;
    
        switch(true){
            
            // detect codes that are too short
            case (sScanCode.length<oOptions.minLength):
                var oScanError = {
                    message: "Receieved code is shorter then minimal length"
                };
                break;
                
            // detect codes that were entered too slow    
            case ((iLastCharTime - iFirstCharTime) > (sScanCode.length * oOptions.avgTimeByChar)):
                var oScanError = {
                    message: "Receieved code was not entered in time"
                };                
                break;
                
            // if a code was not filtered out earlier it is valid    
            default:
                oOptions.onScan.call(oDomElement, sScanCode, iSingleScanQty);
                var oEvent = new CustomEvent(
                    'scan',
                    {    
                        detail: { 
                            scanCode: sScanCode,
                            qty: iSingleScanQty
                        }
                    }
                );
                oDomElement.dispatchEvent(oEvent);
                onScan._reinitialize(oDomElement);
                return true;
        }
        
        // If an error occurred (otherwise the method would return earlier) create an object for errordetection
        oScanError.scanCode = sScanCode;
        oScanError.scanDuration = iLastCharTime - iFirstCharTime;
        oScanError.avgTimeByChar = oOptions.avgTimeByChar;
        oScanError.minLength = oOptions.minLength;
        
        oOptions.onScanError.call(oDomElement, oScanError);
        
        var oEvent = new CustomEvent(
            'scanError',
            oScanError
        );
        oDomElement.dispatchEvent(oEvent);
        
        onScan._reinitialize(oDomElement);
        return false;
        
    },

    _mergeOptions: function(oDefaults, oOptions){
        var oExtended = {};
        var prop;
        for (prop in oDefaults){
            if (Object.prototype.hasOwnProperty.call(oDefaults, prop)){
                oExtended[prop] = oDefaults[prop];
            }
        }            
        for (prop in oOptions){
            if (Object.prototype.hasOwnProperty.call(oOptions, prop)){
                oExtended[prop] = oOptions[prop];
            }
        }            
        return oExtended;
    },

    _getNormalizedKeyNum: function(e){
        var iKeyCode;  
        if(window.event) { // IE                    
          iKeyCode = e.keyCode;
        } else if(e.which){ // Netscape/Firefox/Opera                   
          iKeyCode = e.which;
        }
        return iKeyCode;
    },



    _handleKeyDown: function(e){
        // overwrite the which value of the event with keycode for cross platform compatibility
        e.which = onScan._getNormalizedKeyNum(e);
        var iKeyCode = e.which;
        var oOptions = this['scannerDetectionData'].options;
        var oVars = this['scannerDetectionData'].vars;
        
        oOptions.onKeyDetect.call(this, e.which, e);        
        
        if (onScan._isFocusOnIgnoredElement(this)){
            return;
        }
                    
        // If it's just the button of the scanner, ignore it and wait for the real input
        if(oOptions.scanButtonKeyCode !== false && iKeyCode==oOptions.scanButtonKeyCode) {
            
            // if the button was first pressed, start a timeout for the callback, which gets interrupted if the scanbutton gets released
            if (!oVars.longPressed){
                oVars.longPressTimer = setTimeout( oOptions.onScanButtonLongPress, oOptions.scanButtonLongPressTime, this);
                oVars.longPressed = true;
            }

            return;
        }
        
        if(oOptions.stopPropagation){
            e.stopImmediatePropagation();
        }
        
        if(oOptions.preventDefault){
            e.preventDefault();
        }
        
        switch(true){
            // If it's not the first character and we encounter a terminating character, trigger scan process
            case (oVars.firstCharTime && oOptions.suffixKeyCodes.indexOf(iKeyCode)!==-1):
                e.preventDefault();
                e.stopImmediatePropagation();
                this['scannerDetectionData'].vars.callIsScanner=true;
                break;
                
            // If it's the first character and we encountered one of the starting characters, don't process the scan    
            case (!oVars.firstCharTime && oOptions.prefixKeyCodes.indexOf(iKeyCode)!==-1):
                e.preventDefault();
                e.stopImmediatePropagation();
                oVars.callIsScanner=false;
                break;
                
            // Otherwise, just add the character to the scan string we're building    
            default:
                var character = oOptions.keyCodeMapper.call(this, e);
                if (character === null){
                    return;
                }
                oVars.stringWriting += character;
                oVars.callIsScanner=false;
                break;
        }
        
        if(!oVars.firstCharTime){
            oVars.firstCharTime=Date.now();
        }
        
        oVars.lastCharTime=Date.now();

        if(oVars.testTimer){ 
            clearTimeout(oVars.testTimer);
        }
        
        if(oVars.callIsScanner){
            onScan._validateScanCode(this);
            oVars.testTimer=false;
        } else {
            oVars.testTimer=setTimeout(onScan._validateScanCode, oOptions.timeBeforeScanTest, this);
        }

        oOptions.onKeyProcess.call(this, character, e);
        
    },
    
    _handlePaste: function(e){

        // if the focus is on an ignored element, abort
        if (onScan._isFocusOnIgnoredElement(this)){
            return;
        }
        e.preventDefault();
                    
        var sPasteString = (event.clipboardData || window.clipboardData).getData('text');
        this.scannerDetectionData.options.onPaste.call(this, sPasteString, event);
        
        var oVars = this.scannerDetectionData.vars;
        oVars.firstCharTime = 0;
        oVars.lastCharTime = 0;
        oVars.stringWriting = sPasteString;
        
        // validate the string
        onScan._validateScanCode(this);

    },
    
    _handleKeyUp: function(e){
        // if the focus is on an ignored element, abort
        if (onScan._isFocusOnIgnoredElement(this)){
            return;
        }
        
        var iKeyCode = onScan._getNormalizedKeyNum(e);
        
        // if hardware key is not being pressed anymore stop the timeout and reset
        if (iKeyCode == this.scannerDetectionData.options.scanButtonKeyCode){
            clearTimeout(this.scannerDetectionData.vars.longPressTimer);
            this.scannerDetectionData.vars.longPressed = false;
        }
        
        
        
    }
        
        
};

 

 

================================

使用方法:

            var $OtherSideNo = $("#OtherSideNo");
            onScan.attachTo($OtherSideNo[0], {
                suffixKeyCodes: [13], // 扫描结束时需要输入回车键
                reactToKeydown: true,//对按键作出反应
                reactToPaste: true, // 与粘贴模式(与键盘模式相对)的内置扫描仪兼容
                onScan: function (sCode, iQty) { //替代document.addEventListener('scan')
                    console.log('Scanned: ' + iQty + 'x ' + sCode);
                    $OtherSideNo.change();
                    $('#CartonNo').focus();
                },
                onKeyDetect: function (iKeyCode) { //输出所有可能相关的按键事件-非常适合调试!
                    console.log('Pressed: ' + iKeyCode);
                },

                //禁止粘贴
                onPaste: function (sPasted, oEvent) {
                    $OtherSideNo.val('');
                    $OtherSideNo.focus();
                },
                //扫描错误(用来检测是否键盘输入),禁止键盘输入
                onScanError:function(oDebug) {
                    $OtherSideNo.val('');
                    $OtherSideNo.focus();
                }
            });

 



posted @ 2019-11-29 09:52  岭南春  阅读(746)  评论(0编辑  收藏  举报