標(biāo)簽可以將其 “editable” 屬性設(shè)為 true,而這里采用的是給其設(shè)一個(gè) tabindex 值。代碼如下:
$ele.attr('tabindex', 1);
另外,焦點(diǎn)事件的觸發(fā)需要點(diǎn)擊元素或者 TAB 切換,而這并不符合人類的直覺,因此需要監(jiān)聽鼠標(biāo)移入事件,使目標(biāo)元素“自動(dòng)”地獲得焦點(diǎn):
$ele.on('mouseenter', function(){
$ele.focus();
});
2. 監(jiān)聽鍵盤事件
由于項(xiàng)目面向的客戶所使用的瀏覽器以chrome為主(實(shí)際上是36x瀏覽器),因此沒(méi)有針對(duì)瀏覽器做任何適配,僅僅使用了 jQuery的事件監(jiān)聽:
$ele.on('keydown', this._keyDownHandler.bind(this));
由于實(shí)現(xiàn)是控件化的,所以定義了一個(gè)私有方法 _keyDownHandler 來(lái)響應(yīng)鍵盤的動(dòng)作。
3. 按鍵事件甄別
jQuery事件監(jiān)聽器返回的事件對(duì)象信息較多,因此需要進(jìn)行甄別,為此定義了一個(gè)私有方法 _keyCodeProcess 來(lái)處理按鍵
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 是一個(gè)類似于查找表的對(duì)象,里面存儲(chǔ)了 ctrl、shift、alt按鈕的各種類型組合,每種組合下又分別按照按鍵碼存儲(chǔ)一個(gè)自定義事件類型字符串,事件發(fā)生之后會(huì)從這里返回這個(gè)字符串,當(dāng)然,沒(méi)有對(duì)應(yīng)自定義事件的時(shí)候,就老老實(shí)實(shí)地返回空字符串。
4. 事件分發(fā)
_keyCodeProcess 方法從事件中提取出了事件類型,我們提前將監(jiān)聽的回調(diào)函數(shù)存儲(chǔ)在一個(gè)查找表 callback 中,并且“巧妙”地使得其鍵名剛好為自定義事件字符串前面加個(gè)“on”前綴,就可以方便地調(diào)用了,前述 _keyDownHandler 正是為此而設(shè)計(jì)的:
function _keyDownHandler(e){
var strCommand = this._keyCodeProcess(e);
var objEvent = {
type: '',
originEvent: e.originEvent
};
strCommand && this.callback['on' + strCommand](objEvent);
return null;
};
5. 事件訂閱與解除訂閱
前面說(shuō)了,我們是把回調(diào)函數(shù)存儲(chǔ)起來(lái)適時(shí)調(diào)用的,因此需要對(duì)外暴露一個(gè)“訂閱”接口,讓開發(fā)者可以方便地把自己的回調(diào)函數(shù)存儲(chǔ)到對(duì)象實(shí)例中去,為此,我定義了一個(gè) .bind接口:
function bind(type, callback, description){
var allType = this.allEventType;
if(allType.indexOf(type) === -1){
throwError('不支持改事件類型,請(qǐng)先擴(kuò)展該類型,或采用其他事件類型');
}
if(!(callback instanceof Function)){
throwError('綁定的事件處理回調(diào)必須是函數(shù)類型');
}
this.callback['on' + type] = callback;
this.eventDiscibeSet[type] = description || '沒(méi)有該事件的描述';
return this;
};
由于是給人用的,所以順帶做了下類型檢查。
根據(jù)接口的“對(duì)稱性”,有訂閱最好也有解除訂閱,因此定義了 .unbind接口,只有一句代碼,實(shí)現(xiàn)如下:
function unbind(type){
this.callback['on' + type] = this._emptyEventHandler;
return this;
};
6.擴(kuò)展自定義事件類型
鍵盤事件的組合豐富多彩,如果全部?jī)?nèi)置在控件中的話,會(huì)是很臃腫的,因此除了少數(shù)幾個(gè)常見的組合鍵之外,開發(fā)者可以通過(guò) .extendEventType 方法,來(lái)自定義組合鍵和返回的字符串:
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
是一個(gè)私有方法,用來(lái)寫入自定義鍵盤事件的方法:
_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;
};
這樣,一個(gè)鍵盤事件監(jiān)聽控件就大功告成了,下面是完整實(shí)現(xiàn)代碼:
/**
* @constructor 鍵盤事件監(jiān)聽器
* */
function KeyboardListener(param){
this._init(param);
}
!function(){
/**
* @private {String} param.ele 事件對(duì)象選擇器
* */
KeyboardListener.prototype._init = function _init(param){
this.$ele = $(param.ele);
this._initEvents();
this._initEventType();
return null;
};
/**
* @private _emptyEventHandler 空白事件響應(yīng)
* */
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: {}
};
// 支持一些內(nèi)建的鍵盤事件類型
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 自定義鍵盤事件分發(fā)
* */
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 擴(kuò)展鍵盤事件類型
* @param {Object|Array
關(guān)于使用jQuery怎么實(shí)現(xiàn)一個(gè)鍵盤事件監(jiān)聽控件就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。
文章標(biāo)題:使用jQuery怎么實(shí)現(xiàn)一個(gè)鍵盤事件監(jiān)聽控件
當(dāng)前網(wǎng)址:
http://weahome.cn/article/ggsdjc.html