jQueryベースのキーボードイベントリスニングコントロール

13565 ワード

最近のプロジェクトでは、撤回、やり直し、移動、スケールなどのショートカットキー操作を行うために、キーボードイベントのリスニングを行う必要があります.そのため、キーボードイベントのリスニングコントロールを実現しました.
1.オートフォーカス
ブラウザのキーボードイベントは、フォーカスを取得できる要素によってのみリスニングが設定されるようですが、通常、イベントをリスニングする必要があり、要素がフォーカスを取得できないため、ターゲット要素の一部の属性を変更してフォーカスを取得する必要があります.もう1つの実行可能な方法は、ラベルなどのイベントを委任することです.ここでは第1の方法を採用しています.もちろん、変更できる属性も1つだけではありません.例えば、ラベルについては「editable」属性をtrueに設定することができますが、ここではtabindex値を設定することができます.コードは次のとおりです.
        $ele.attr('tabindex', 1);     

また、フォーカスイベントのトリガには、人間の直感に合わない要素またはTABをクリックして切り替える必要があります.そのため、マウスがイベントに移動するのを監視し、ターゲット要素が自動的にフォーカスを得る必要があります.
$ele.on('mouseenter', $ele.focus);

2.キーボードイベントのリスニング
プロジェクト向けのお客様が使用するブラウザはchromeがメイン(実際には36 xブラウザ)であるため、ブラウザに適したものはなく、jQueryのイベントリスニングのみを使用しています.
        $ele.on('keydown', this._keyDownHandler.bind(this));
        

インプリメンテーションはコントロール化されているため、プライベートメソッドが定義されています.keyDownHandlerはキーボードの動作に応答します.
3.キーイベント選別
jQueryイベントリスナーが返すイベントオブジェクト情報が多いため、識別が必要であるため、プライベートメソッドを定義した.キーコードプロセスでキーを処理
function _keyCodeProcess(e){
        var code = e.keyCode + '';
        var altKey = e.altKey;
        var ctrlKey = e.ctrlKey;
        var shiftKey = e.shiftKey;

        var threeKey = altKey && ctrlKey && shiftKey;
        var ctrlAlt = altKey && ctrlKey;
        var altShift = altKey && shiftKey;
        var ctrlShift = shiftKey && ctrlKey;

        var keyTypeSet = this.keyTypeSet;
        var resStr = '';

        if(threeKey){
            resStr = keyTypeSet.threeKey[code];
        } else if(ctrlAlt) {
            resStr = keyTypeSet.ctrlAlt[code];
        } else if(ctrlShift) {
            resStr = keyTypeSet.ctrlShift[code];
        } else if(altShift) {
            resStr = keyTypeSet.altShift[code];
        } else if(altKey) {
            resStr = keyTypeSet.altKey[code];
        } else if(ctrlKey) {
            resStr = keyTypeSet.ctrlKey[code];
        } else if(shiftKey) {
            resStr = keyTypeSet.shiftKey[code];
        } else {
            resStr = keyTypeSet.singleKey[code];
        }

        return resStr
    };
    

ここでkeyTypeSetは、ctrl、shift、altボタンの様々なタイプの組み合わせが格納されたルックアップテーブルのようなオブジェクトで、それぞれの組み合わせの下でキーコードに従ってカスタムイベントタイプ文字列が格納され、イベントが発生するとここからこの文字列が返されます.もちろん、カスタムイベントに対応していない場合、空の文字列を正直に返します.
4.イベント配信
_keyCodeProcessメソッドはイベントからイベントタイプを抽出し、事前にリスニングされたコールバック関数をルックアップテーブルcallbackに格納し、キー名がカスタムイベント文字列の前にちょうど「on」接頭辞を付けるように「巧みに」すれば、前述の_keyDownHandlerはこのために設計されています.
function _keyDownHandler(e){
        var strCommand = this._keyCodeProcess(e);

        var objEvent = {
            type: '',
            originEvent: e.originEvent
        };

        strCommand && this.callback['on' + strCommand](objEvent);

        return null;
    };
    
    

5.イベント購読と購読解除
前述のように、コールバック関数を適時に呼び出すために、開発者が自分のコールバック関数をオブジェクトインスタンスに簡単に格納できるように、「サブスクリプション」インタフェースを外部に露出する必要がある.bindインタフェース:
function bind(type, callback, description){
        var allType = this.allEventType;
        if(allType.indexOf(type) === -1){
            throwError('        ,       ,         ');
        }

        if(!(callback instanceof Function)){
            throwError('                ');
        }

        this.callback['on' + type] = callback;

        this.eventDiscibeSet[type] = description || '        ';

        return this;
    };
    

人用なので、ついでにタイプチェックをしてみました.インタフェースの「対称性」によっては,サブスクリプションがある方がよいし,サブスクリプションを解除する方がよいので定義する.unbindインタフェースは、コードが1つしかなく、以下のように実現されます.
function unbind(type){
        this.callback['on' + type] = this._emptyEventHandler;

        return this;
    };
    

6.カスタムイベントタイプの拡張
キーボードイベントの組み合わせは多彩で、すべてコントロールに内蔵と肥大化するため、いくつかの一般的な組み合わせキーを除いて、開発者は通過することができる.extendEventTypeメソッドは、結合キーと返される文字列を定義する方法です.
function extendEventType(config){
        var len = 0;
        if(config instanceof Array){
            len = config.length;
            while(len--){
                this._setKeyComposition(config[len]);
            }
        } else {
            this._setKeyComposition(config);
        }
        return this;
    };
    

の.setKeyCompositionは、カスタムキーボードイベントを書き込むプライベートメソッドです.
function _setKeyComposition(config){
        var altKey = config.alt;
        var ctrlKey = config.ctrl;
        var shiftKey = config.shift;

        var threeKey = altKey && ctrlKey && shiftKey;
        var ctrlAlt = altKey && ctrlKey;
        var altShift = altKey && shiftKey;
        var ctrlShift = shiftKey && ctrlKey;
        var code = config.code + '';

        if(threeKey){
            this.keyTypeSet.threeKey[code] = config.type;
        } else if(ctrlAlt) {
            this.keyTypeSet.ctrlAlt[code] = config.type;
        } else if(ctrlShift) {
            this.keyTypeSet.ctrlShift[code] = config.type;
        } else if(altShift) {
            this.keyTypeSet.altShift[code] = config.type;
        } else if(altKey) {
            this.keyTypeSet.altKey[code] = config.type;
        } else if(ctrlKey) {
            this.keyTypeSet.ctrlKey[code] = config.type;
        } else if(shiftKey) {
            this.keyTypeSet.shiftKey[code] = config.type;
        } else {
            this.keyTypeSet.singleKey[code] = config.type;
        }
        
        this.allEventType.push(type);
        this.callback['on' + type] = this._emptyEventHandler;

        return null;
    };
    

これにより、キーボードイベントのリスニングコントロールが完成し、次の完全な実装コードが得られます.
/**
 * @constructor        
 * */
function KeyboardListener(param){
    this._init(param);
}

!function(){
    'use strict';

    /**
     * @private {String} param.ele        
     * */
    KeyboardListener.prototype._init = function _init(param){
        this.$ele = $(param.ele);

        this._initEvents();

        return null;
    };

    /**
     * @private _emptyEventHandler       
     * */
    KeyboardListener.prototype._emptyEventHandler = function _emptyEventHandler(){
        return null;
    };

    /**
     * @private _initEvents    DOM   
     * */
    KeyboardListener.prototype._initEvents = function _initEvents(){
        this.allEventType = [];
        this.callback = {};
        this.eventDiscibeSet = {};

        var $ele = this.$ele;

        $ele.attr('tabindex', 1);

        $ele.on('mouseenter', function(){
            $ele.focus();
        });

        $ele.on('keydown', this._keyDownHandler.bind(this));

        this.keyTypeSet = {
            altKey: {},
            ctrlAlt: {},
            ctrlKey: {},
            threeKey: {},
            altShift: {},
            shiftKey: {},
            ctrlShift: {},
            singleKey: {}
        };

        //              
        this.extendEventType([
            {
                type: 'redo',
                ctrl: true,
                shift: true,
                code: 90
            },
            {
                type: 'undo',
                ctrl: true,
                code: 90
            },
            {
                type: 'copy',
                ctrl: true,
                code: 67
            },
            {
                type: 'paste',
                ctrl: true,
                code: 86
            },
            {
                type: 'delete',
                code: 46
            },
            {
                type: 'right',
                code: 39
            },
            {
                type: 'down',
                code: 40
            },
            {
                type: 'left',
                code: 37
            },
            {
                type: 'up',
                code: 38
            }
        ]);

        return null;
    };

    /**
     * @private _keyDownHandler          
     * */
    KeyboardListener.prototype._keyDownHandler = function _keyDownHandler(e){
        var strCommand = this._keyCodeProcess(e);

        var objEvent = {
            type: '',
            originEvent: e.originEvent
        };

        strCommand && this.callback['on' + strCommand](objEvent);

        return null;
    };

    /**
     * @private _keyCodeProcess      
     * */
    KeyboardListener.prototype._keyCodeProcess = function _keyCodeProcess(e){
        var code = e.keyCode + '';
        var altKey = e.altKey;
        var ctrlKey = e.ctrlKey;
        var shiftKey = e.shiftKey;

        var threeKey = altKey && ctrlKey && shiftKey;
        var ctrlAlt = altKey && ctrlKey;
        var altShift = altKey && shiftKey;
        var ctrlShift = shiftKey && ctrlKey;

        var keyTypeSet = this.keyTypeSet;
        var resStr = '';

        if(threeKey){
            resStr = keyTypeSet.threeKey[code];
        } else if(ctrlAlt) {
            resStr = keyTypeSet.ctrlAlt[code];
        } else if(ctrlShift) {
            resStr = keyTypeSet.ctrlShift[code];
        } else if(altShift) {
            resStr = keyTypeSet.altShift[code];
        } else if(altKey) {
            resStr = keyTypeSet.altKey[code];
        } else if(ctrlKey) {
            resStr = keyTypeSet.ctrlKey[code];
        } else if(shiftKey) {
            resStr = keyTypeSet.shiftKey[code];
        } else {
            resStr = keyTypeSet.singleKey[code];
        }

        return resStr
    };

    /**
     * @private _setKeyComposition        
     * @param {Object} config         
     * @param {String} config.type        
     * @param {keyCode} config.code      
     * @param {Boolean} [config.ctrl]     Ctrl      
     * @param {Boolean} [config.alt]     Alt      
     * @param {Boolean} [config.shift]     Shift      
     * */
    KeyboardListener.prototype._setKeyComposition = function _setKeyComposition(config){
        var altKey = config.alt;
        var ctrlKey = config.ctrl;
        var shiftKey = config.shift;

        var threeKey = altKey && ctrlKey && shiftKey;
        var ctrlAlt = altKey && ctrlKey;
        var altShift = altKey && shiftKey;
        var ctrlShift = shiftKey && ctrlKey;
        var code = config.code + '';
        var type = config.type;

        if(threeKey){
            this.keyTypeSet.threeKey[code] = type;
        } else if(ctrlAlt) {
            this.keyTypeSet.ctrlAlt[code] = type;
        } else if(ctrlShift) {
            this.keyTypeSet.ctrlShift[code] = type;
        } else if(altShift) {
            this.keyTypeSet.altShift[code] = type;
        } else if(altKey) {
            this.keyTypeSet.altKey[code] = type;
        } else if(ctrlKey) {
            this.keyTypeSet.ctrlKey[code] = type;
        } else if(shiftKey) {
            this.keyTypeSet.shiftKey[code] = type;
        } else {
            this.keyTypeSet.singleKey[code] = type;
        }
        this.allEventType.push(type);
        this.callback['on' + type] = this._emptyEventHandler;
        // this.eventDiscibeSet = {};

        return null;
    };

    /**
     * @method extendEventType         
     * @param {Object|Array} config         
     * @param {String} config.type        
     * @param {keyCode} config.code      
     * @param {Boolean} [config.ctrl]     Ctrl      
     * @param {Boolean} [config.alt]     Alt      
     * @param {Boolean} [config.shift]     Shift      
     * */
    KeyboardListener.prototype.extendEventType = function extendEventType(config){
        var len = 0;
        if(config instanceof Array){
            len = config.length;
            while(len--){
                this._setKeyComposition(config[len]);
            }
        } else {
            this._setKeyComposition(config);
        }
        return this;
    };

    /**
     * @method bind           
     * @param {String} type       :['up', 'down', 'left', 'right', 'undo', 'redo', 'delete', zoomIn, 'zoomOut']
     * @param {Function} callback     ,              
     * @param {String} description             
     * */
    KeyboardListener.prototype.bind = function bind(type, callback, description){
        var allType = this.allEventType;
        if(allType.indexOf(type) === -1){
            throwError('        ,       ,         ');
        }

        if(!(callback instanceof Function)){
            throwError('                ');
        }

        this.callback['on' + type] = callback;

        this.eventDiscibeSet[type] = description || '        ';

        return this;
    };

    /**
     * @method unbind       
     * @param {String} type     
     * */
    KeyboardListener.prototype.unbind = function unbind(type){
        this.callback['on' + type] = this._emptyEventHandler;

        return this;
    };
    
    return null;
}();