No element can get focus, so you need to modify some properties of the target element so that it can get focus. Another possible method is to delegate the event to a tag such as . The first type of method is used here. Of course, there is more than one attribute that can be modified. For example, for the tag, you can set its "editable" attribute to true, but what is used here is to set a tabindex value for it. . The code is as follows:
$ele.attr('tabindex', 1);
In addition, the triggering of the focus event requires clicking on the element or TAB switching, which is not in line with human intuition. Therefore, it is necessary to monitor the mouse move-in event so that the target element can "automatically" gain focus:
$ele.on('mouseenter', function(){
$ele.focus();
});
2. Listening to keyboard events
Since the browser used by the customers for the project is mainly chrome (actually 36x browser), no adaptation has been made to the browser. Only jQuery's event monitoring is used:
$ele.on('keydown', this._keyDownHandler.bind(this));
Since the implementation is control-oriented, a private method _keyDownHandler is defined to respond to keyboard actions.
3. Key event screening
jQuery event listener returns a lot of event object information, so it needs to be screened. For this purpose, a private method _keyCodeProcess is defined to handle key presses
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
}; The keyTypeSet here is an object similar to a lookup table, which stores various types of combinations of ctrl, shift, and alt buttons. Under each combination, a custom event type string is stored according to the key code. When the event occurs This string will be returned from here later. Of course, when there is no corresponding custom event, an empty string will be returned honestly.
4. Event distribution
_keyCodeProcess method extracts the event type from the event. We store the listening callback function in a lookup table callback in advance, and "cleverly" make its key The name just adds "on" prefix in front of the custom event string, and it can be easily called. The aforementioned _keyDownHandler is designed for this:
function _keyDownHandler(e){
var strCommand = this._keyCodeProcess(e);
var objEvent = {
type: '',
originEvent: e.originEvent
};
strCommand && this.callback['on' + strCommand](objEvent);
return null;
};
5. Event subscription and unsubscription
As mentioned earlier, we store the callback function and call it in a timely manner, so we need to expose a "subscription" interface so that developers can easily store their callback function into the object instance. For this reason, I defined a .bind interface:
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;
};
Since it is for human use, I did a type check by the way. According to the "symmetry" of the interface, it is best to subscribe and unsubscribe, so the .unbind interface is defined, with only one line of code, and the implementation is as follows:
function unbind(type){
this.callback['on' + type] = this._emptyEventHandler;
return this;
};
6. Extend the custom event type The combinations of keyboard events are rich and colorful. If they are all built into the control, it will be very bloated. Therefore, in addition to a few common key combinations, developers can customize key combinations and returns through the .extendEventType method. String:
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;
};
The ._setKeyComposition is a private method used to write custom keyboard events:
_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;
};
In this way, a keyboard event listening control is complete, as follows Is the complete implementation code:
/**
* @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;
};
}();
[Related recommendations: jQuery video tutorial ]
The above is the detailed content of Introduction to jQuery-based keyboard event listening control (code example). For more information, please follow other related articles on the PHP Chinese website!