Handling Keyboard Shortcuts in JavaScript
在web开发中,对页面的进行全局或部分页面进行键盘快捷键事件注册,能够有效的提高页面的用户体验。在ExtJs中的表格Form中就有回车提交的事件,实现方法可以参照我的另一篇文章:Ext监控回车按键。
在网络上看到了一篇处理JavaScript键盘快捷键事件的文章:Handling Keyboard Shortcuts in JavaScript ,其实现方法很简单,只是封装了一个shortcut的类,提供了注册快捷键的方法和删除快捷键事件的方法。
其源代码如下,其中代码逻辑很容易看懂而且其中考虑了各种浏览器的兼容问题(可以参照我的上一篇文章:DOM 事件模型)。通过以下代码,可以熟悉如何处理各种浏览器事件处理的兼容性问题。
/**
* http://www.openjs.com/scripts/events/keyboard_shortcuts/ Version : 2.01.B By
* Binny V A License : BSD
* Modified by www.javachen.com javachen
*/
shortcut = {
'all_shortcuts' : {},// All the shortcuts are stored in this array
'add' : function(shortcut_combination, callback, opt) {
// Provide a set of default options
var default_options = {
'type' : 'keydown',//按键事件类型,IE中keypress不支持功能按键,所以应该用keydown/keyup事件来进行补充。
'propagate' : false,
'disable_in_input' : false,//是否在input,Textarea内有效
'target' : document,//事件作用对象,相当于事件的相应范围scope,该值可以为节点的ID
'keycode' : false
}
//处理配置项,如果为空就使用默认的
if (!opt)
opt = default_options;
else {
for (var dfo in default_options) {
if (typeof opt[dfo] == 'undefined')
opt[dfo] = default_options[dfo];
}
}
//如果target为字符串,则通过该字符串取得该DOM对象
var ele = opt.target;
if (typeof opt.target == 'string')
ele = document.getElementById(opt.target);
var ths = this;//保存当前的this引用
//联合快捷键
shortcut_combination = shortcut_combination.toLowerCase();
// The function to be called at keypress
var func = function(e) {
e = e || window.event;//处理浏览器对event的兼容性,只有IE浏览器的event=window.event
if (opt['disable_in_input']) { // Don't enable shortcut keys in
// Input, Textarea fields
var element;
if (e.target)
//针对IE浏览器
element = e.target;
else if (e.srcElement)
//针对DOM标准浏览器
element = e.srcElement;
//如果当前节点为文本节点,则取其父节点
if (element.nodeType == 3)
element = element.parentNode;
//如果当前节点标签名为INPUT或TEXTAREA,则当前函数不做处理
if (element.tagName == 'INPUT' || element.tagName == 'TEXTAREA')
return;
}
// Find Which key is pressed
if (e.keyCode)
//针对IE浏览器,e.keyCode返回按键对应的数值
code = e.keyCode;
else if (e.which)
//针对DOM标准浏览器,如Firefox,e.keyCode返回按键对应的数值
code = e.which;
//e.which将给出该键的索引值,把索引值转化成该键的字母或数字值的方法需要用到静态函数String.fromCharCode()
var character = String.fromCharCode(code).toLowerCase();
if (code == 188)
character = ",";
if (code == 190)
character = ".";
var keys = shortcut_combination.split("+");
// Key Pressed - counts the number of valid keypresses - if it is
// same as the number of keys, the shortcut function is invoked
var kp = 0;
// Work around for stupid Shift key bug created by using lowercase -
// as a result the shift+num combination was broken
var shift_nums = {
"`" : "~",
"1" : "!",
"2" : "@",
"3" : "#",
"4" : "$",
"5" : "%",
"6" : "^",
"7" : "&",
"8" : "*",
"9" : "(",
"0" : ")",
"-" : "_",
"=" : "+",
";" : ":",
"'" : "\"",
"," : "<",
"." : ">",
"/" : "?",
"\\" : "|"
}
// Special Keys - and their codes
var special_keys = {
'esc' : 27,
'escape' : 27,
'tab' : 9,
'space' : 32,
'return' : 13,
'enter' : 13,
'backspace' : 8,
'scrolllock' : 145,
'scroll_lock' : 145,
'scroll' : 145,
'capslock' : 20,
'caps_lock' : 20,
'caps' : 20,
'numlock' : 144,
'num_lock' : 144,
'num' : 144,
'pause' : 19,
'break' : 19,
'insert' : 45,
'home' : 36,
'delete' : 46,
'end' : 35,
'pageup' : 33,
'page_up' : 33,
'pu' : 33,
'pagedown' : 34,
'page_down' : 34,
'pd' : 34,
'left' : 37,
'up' : 38,
'right' : 39,
'down' : 40,
'f1' : 112,
'f2' : 113,
'f3' : 114,
'f4' : 115,
'f5' : 116,
'f6' : 117,
'f7' : 118,
'f8' : 119,
'f9' : 120,
'f10' : 121,
'f11' : 122,
'f12' : 123
}
var modifiers = {
shift : {
wanted : false,
pressed : false//是否被按
},
ctrl : {
wanted : false,
pressed : false
},
alt : {
wanted : false,
pressed : false
},
meta : {
wanted : false,
pressed : false
} // Meta is Mac specific
};
if (e.ctrlKey)
modifiers.ctrl.pressed = true;
if (e.shiftKey)
modifiers.shift.pressed = true;
if (e.altKey)
modifiers.alt.pressed = true;
if (e.metaKey)
modifiers.meta.pressed = true;
for (var i = 0; k = keys[i], i < keys.length; i++) {
// Modifiers
if (k == 'ctrl' || k == 'control') {
kp++;
modifiers.ctrl.wanted = true;
} else if (k == 'shift') {
kp++;
modifiers.shift.wanted = true;
} else if (k == 'alt') {
kp++;
modifiers.alt.wanted = true;
} else if (k == 'meta') {
kp++;
modifiers.meta.wanted = true;
} else if (k.length > 1) { // If it is a special key
if (special_keys[k] == code)
kp++;
} else if (opt['keycode']) {
if (opt['keycode'] == code)
kp++;
} else { // The special keys did not match
if (character == k)
kp++;
else {
if (shift_nums[character] && e.shiftKey) { // Stupid
// Shift key
// bug
// created
// by using
// lowercase
character = shift_nums[character];
if (character == k)
kp++;
}
}
}
}
if (kp == keys.length
&& modifiers.ctrl.pressed == modifiers.ctrl.wanted
&& modifiers.shift.pressed == modifiers.shift.wanted
&& modifiers.alt.pressed == modifiers.alt.wanted
&& modifiers.meta.pressed == modifiers.meta.wanted) {
callback(e);
if (!opt['propagate']) { // Stop the event
// e.cancelBubble is supported by IE - this will kill the
// bubbling process.
e.cancelBubble = true;
e.returnValue = false;
// e.stopPropagation works in Firefox.
if (e.stopPropagation) {
e.stopPropagation();
e.preventDefault();
}
return false;
}
}
}
this.all_shortcuts[shortcut_combination] = {
'callback' : func,
'target' : ele,
'event' : opt['type']
};
// Attach the function with the event
if (ele.addEventListener)
ele.addEventListener(opt['type'], func, false);
else if (ele.attachEvent)
ele.attachEvent('on' + opt['type'], func);
else
ele['on' + opt['type']] = func;
},
// Remove the shortcut - just specify the shortcut and I will remove the
// binding
'remove' : function(shortcut_combination) {
shortcut_combination = shortcut_combination.toLowerCase();
var binding = this.all_shortcuts[shortcut_combination];
delete(this.all_shortcuts[shortcut_combination])
if (!binding)
return;
var type = binding['event'];
var ele = binding['target'];
var callback = binding['callback'];
if (ele.detachEvent)
ele.detachEvent('on' + type, callback);
else if (ele.removeEventListener)
ele.removeEventListener(type, callback, false);
else
ele['on' + type] = false;
}
}