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

1. 自动获取焦点

似乎浏览器的键盘事件只能被那些可以获得焦点的元素设置监听,而通常需要监听事件的

、 元素都不能获得焦点,因此需要修改目标元素的某些属性使其可以获得焦点,另外一种可行的方法是将事件委托给诸如 标签。这里采用的是第一类方法,当然,可以修改的属性也不止一种,例如,对于

标签可以将其 “editable” 属性设为 true,而这里采用的是给其设一个 tabindex 值。代码如下:

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

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

$ele.on('mouseenter', function(){

$ele.focus();

});

2. 监听键盘事件

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

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

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

3. 按键事件甄别

jQuery事件监听器返回的事件对象信息较多,因此需要进行甄别,为此定义了一个私有方法 _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

};

这里的 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接口,只有一句代码,实现如下:

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 是一个私有方法,用来写入自定义键盘事件的方法:

_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;

};

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

/**

* @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} 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 实现键盘事件监听控件,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

jquery实现上下左右键盘监听_基于 jQuery 实现键盘事件监听控件相关推荐

  1. global 仪表控件 无人机地面站_基于GL Studio的无人机地面站天线控件设计与实现...

    基于 GL Studio 的无人机地面站天线控件设计与实现 李兴岷 ; 陈怀民 ; 喻戈 ; 任伟 [期刊名称] <测控技术> [年 ( 卷 ), 期] 2011(030)009 [摘要] ...

  2. 事件监听机制(一)Java事件监听

    事件监听机制(一)Java事件监听 事件监听实现流程 事件对象: 继承自java.util.EventObject对象,由开发者自行定义实现. 事件源: 就是触发事件的源头,不同的事件源会触发不同的事 ...

  3. SAP UI5 应用开发教程之六十六 - 基于 OData V4 的 SAP UI5 表格控件如何实现删除功能试读版

    一套适合 SAP UI5 初学者循序渐进的学习教程 教程目录 SAP UI5 本地开发环境的搭建 SAP UI5 应用开发教程之一:Hello World SAP UI5 应用开发教程之二:SAP U ...

  4. SAP UI5 应用开发教程之六十四 - 基于 OData V4 的 SAP UI5 表格控件如何实现 filter(过滤) 和 sort(排序)功能试读版

    一套适合 SAP UI5 初学者循序渐进的学习教程 教程目录 SAP UI5 本地开发环境的搭建 SAP UI5 应用开发教程之一:Hello World SAP UI5 应用开发教程之二:SAP U ...

  5. SAP UI5 应用开发教程之六十二 - 基于 OData V4 的 SAP UI5 表格控件使用方法介绍试读版

    一套适合 SAP UI5 初学者循序渐进的学习教程 教程目录 SAP UI5 本地开发环境的搭建 SAP UI5 应用开发教程之一:Hello World SAP UI5 应用开发教程之二:SAP U ...

  6. SAP UI5 应用开发教程之六十五 - 基于 OData V4 的 SAP UI5 表格控件如何实现创建,编辑和保存功能

    本教程前几个步骤,我们已经用 SAP UI5 table 控件开发了一个包含 User 列表的应用,并且支持了根据 LastName 字段进行查询,以及排序的操作. SAP UI5 应用开发教程之六十 ...

  7. SAP UI5 应用开发教程之六十四 - 基于 OData V4 的 SAP UI5 表格控件如何实现 filter(过滤) 和 sort(排序)功能

    本教程的上一个步骤,我们学习了如何基于 OData V4 开发一个最简单的使用了 Table(表格)控件的 SAP UI5 应用. SAP UI5 应用开发教程之六十二 - 基于 OData V4 的 ...

  8. Jquery系列:checkbox 获取值、选中、设置值、事件监听等操作

    <div id="divId" class="divTable"><div class="tableBody">&l ...

  9. jquery字体颜色_基于jquery实现的web版excel

    基于jquery实现的web版excel.包含excel的基本功能 支持合并单元格,拆分单元格 支持插入单元格,删除单元格 支持整行整列选择单元格 自定义右键菜单,可以设置单元格数量 支持鼠标左键拖动 ...

最新文章

  1. linux 文件查找与文件中注释去除
  2. 批量新建文件夹并命名_dos命令实现批量新建文件夹
  3. jmeter的性能监控框架搭建记录(Influxdb+Grafana+Jmeter)
  4. python:实现简单的web开发demo
  5. paradox 修改字段长度_关于生日的作文500字9篇
  6. 微信小程序php实现登陆的代码,微信小程序实现微信登录
  7. python判断是否为完全数_Python识别完美数
  8. [Erlang07] Erlang 做图形化编程的尝试:纯Erlang做2048游戏
  9. 深入学习webpack(四)
  10. html中的灵动标签,《帝国网站管理系统》一招鲜吃天遍天系列教程之 灵动标签使用...
  11. PHP中各种Hash算法性能比较
  12. 印章识别软件_一种印章识别方法及系统技术方案
  13. 中国电信运营商布局云计算“赛道”面临三大挑战
  14. vector的几种初始化及赋值方式
  15. 做成才还是做许三多——反思程序员职场生涯规划
  16. 休假申请单位取消分钟、小时,增加“.”。
  17. 算法简介:不撞南墙不回头----深度优先搜索算法(DFS)
  18. sql命令手册(转载)http://www.fanqiang.com
  19. P1567 统计天数
  20. 《环球》杂志|“宇宙级”漏洞过后,一个技术总裁的忠告……

热门文章

  1. 基于共享内存、信号、命名管道和Select模型实现聊天窗口
  2. 洛谷P1126 机器人搬重物【bfs】
  3. Articles for objccn.io. objc.io的完整、准确、优雅的中文翻译版本 http://objccn.io/
  4. BeanUtils 使用问题
  5. 对于纯Java项目,JVM 各个类加载器的加载目标是什么?
  6. 【转】xPath语法介绍
  7. 大型网站技术架构(五)--网站高可用架构(转)
  8. Airflow 中文文档:使用测试模式配置
  9. 面向机器学习的特征工程 六、降维:用 PCA 压缩数据集
  10. django 1.8 官方文档翻译:5-2-2 表单素材 ( Media 类)