zoukankan      html  css  js  c++  java
  • 基于 jQuery 实现键盘事件监听控件

    原文链接:https://www.jb51.net/article/159116.htm

    最近项目里要做一个画板,需要对键盘事件进行监听,来进行诸如撤回、重做、移动、缩放等操作,因此顺手实现了一个键盘事件监听控件,期间略有收获,整理出来,希望对大家有所帮助,更希望能获得高手的指点。

    1. 自动获取焦点

    似乎浏览器的键盘事件只能被那些可以获得焦点的元素设置监听,而通常需要监听事件的 <DIV>、<CANVAS> 元素都不能获得焦点,因此需要修改目标元素的某些属性使其可以获得焦点,另外一种可行的方法是将事件委托给诸如 <INPUT> 标签。这里采用的是第一类方法,当然,可以修改的属性也不止一种,例如,对于 <DIV> 标签可以将其 “editable” 属性设为 true,而这里采用的是给其设一个 tabindex 值。代码如下:

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

    另外,焦点事件的触发需要点击元素或者 TAB 切换,而这并不符合人类的直觉,因此需要监听鼠标移入事件,使目标元素“自动”地获得焦点:

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

    2. 监听键盘事件

    由于项目面向的客户所使用的浏览器以chrome为主(实际上是36x浏览器),因此没有针对浏览器做任何适配,仅仅使用了 jQuery的事件监听:

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

    由于实现是控件化的,所以定义了一个私有方法 _keyDownHandler 来响应键盘的动作。

    3. 按键事件甄别

    jQuery事件监听器返回的事件对象信息较多,因此需要进行甄别,为此定义了一个私有方法 _keyCodeProcess 来处理按键

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    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 正是为此而设计的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function _keyDownHandler(e){
        var strCommand = this._keyCodeProcess(e);
        var objEvent = {
          type: '',
          originEvent: e.originEvent
        };
        strCommand && this.callback['on' + strCommand](objEvent);
        return null;
      };

    5. 事件订阅与解除订阅

    前面说了,我们是把回调函数存储起来适时调用的,因此需要对外暴露一个“订阅”接口,让开发者可以方便地把自己的回调函数存储到对象实例中去,为此,我定义了一个 .bind接口:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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
    2
    3
    4
    function unbind(type){
        this.callback['on' + type] = this._emptyEventHandler;
        return this;
      };

    6.扩展自定义事件类型

    键盘事件的组合丰富多彩,如果全部内置在控件中的话,会是很臃肿的,因此除了少数几个常见的组合键之外,开发者可以通过 .extendEventType 方法,来自定义组合键和返回的字符串:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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 是一个私有方法,用来写入自定义键盘事件的方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    _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;
        }
        return null;
      };

    这样,一个键盘事件监听控件就大功告成了,下面是完整实现代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    /**
     * @constructor 键盘事件监听器
     * */
    function KeyboardListener(param){
      this._init(param);
    }
    !function(){
      /**
       * @private {String} param.ele 事件对象选择器
       * */
      KeyboardListener.prototype._init = function _init(param){
        this.$ele = $(param.ele);
        this._initEvents();
        this._initEventType();
        return null;
      };
      /**
       * @private _emptyEventHandler 空白事件响应
       * */
      KeyboardListener.prototype._emptyEventHandler = function _emptyEventHandler(){
        return null;
      };
      /**
       * @private _initEventType 初始化所有初始自定义事件类型
       * */
      KeyboardListener.prototype._initEventType = function _initEventType(){
        var allType = ['up', 'down', 'left', 'right', 'undo', 'redo', 'zoomIn', 'zoomOut', 'delete'];
        var intLen = allType.length;
        this.allEventType = allType;
        this.callback = {};
        this.eventDiscibeSet = {};
        for(var intCnt = 0; intCnt < intLen; intCnt++){
          this.callback['on' + allType[intCnt]] = KeyboardListener.prototype._emptyEventHandler;
        }
        return null;
      };
      /**
       * @private _initEvents 绑定 DOM 事件
       * */
      KeyboardListener.prototype._initEvents = function _initEvents(){
        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 + '';
        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;
        }
        return null;
      };
      /**
       * @method extendEventType 扩展键盘事件类型
       * @param {Object|Array<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.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;
      };
    }();

    总结

    以上所述是小编给大家介绍的基于 jQuery 实现键盘事件监听控件,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

  • 相关阅读:
    Servlet的几种跳转(转)
    Java String.split()用法小结(转)
    表单数据提交的方法
    gedit文本编辑器乱码解决办法
    J-Link烧写bootloader到mini2440的Nor Flash
    虚拟机安装Fedora10系统遇到异常
    linux系统忘记root密码怎么办?
    编译busybox时出错及解决方案
    source insight代码查看器如何自定义添加文件类型
    < Objective-C >文件操作-NSFileHandle
  • 原文地址:https://www.cnblogs.com/jiangyuzhen/p/10977699.html
Copyright © 2011-2022 走看看