溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

使用jQuery怎么實(shí)現(xiàn)一個(gè)鍵盤(pán)事件監(jiān)聽(tīng)控件

發(fā)布時(shí)間:2021-04-20 16:40:01 來(lái)源:億速云 閱讀:484 作者:Leah 欄目:web開(kāi)發(fā)

這篇文章將為大家詳細(xì)講解有關(guān)使用jQuery怎么實(shí)現(xiàn)一個(gè)鍵盤(pán)事件監(jiān)聽(tīng)控件,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

jquery是什么

jquery是一個(gè)簡(jiǎn)潔而快速的JavaScript庫(kù),它具有獨(dú)特的鏈?zhǔn)秸Z(yǔ)法和短小清晰的多功能接口、高效靈活的css選擇器,并且可對(duì)CSS選擇器進(jìn)行擴(kuò)展、擁有便捷的插件擴(kuò)展機(jī)制和豐富的插件,是繼Prototype之后又一個(gè)優(yōu)秀的JavaScript代碼庫(kù),能夠用于簡(jiǎn)化事件處理、HTML文檔遍歷、Ajax交互和動(dòng)畫(huà),以便快速開(kāi)發(fā)網(wǎng)站。

1. 自動(dòng)獲取焦點(diǎn)

似乎瀏覽器的鍵盤(pán)事件只能被那些可以獲得焦點(diǎn)的元素設(shè)置監(jiān)聽(tīng),而通常需要監(jiān)聽(tīng)事件的 <DIV>、<CANVAS> 元素都不能獲得焦點(diǎn),因此需要修改目標(biāo)元素的某些屬性使其可以獲得焦點(diǎn),另外一種可行的方法是將事件委托給諸如 <INPUT> 標(biāo)簽。這里采用的是第一類(lèi)方法,當(dāng)然,可以修改的屬性也不止一種,例如,對(duì)于 <DIV> 標(biāo)簽可以將其 “editable” 屬性設(shè)為 true,而這里采用的是給其設(shè)一個(gè) tabindex 值。代碼如下:

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

另外,焦點(diǎn)事件的觸發(fā)需要點(diǎn)擊元素或者 TAB 切換,而這并不符合人類(lèi)的直覺(jué),因此需要監(jiān)聽(tīng)鼠標(biāo)移入事件,使目標(biāo)元素“自動(dòng)”地獲得焦點(diǎn):

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

2. 監(jiān)聽(tīng)鍵盤(pán)事件

由于項(xiàng)目面向的客戶所使用的瀏覽器以chrome為主(實(shí)際上是36x瀏覽器),因此沒(méi)有針對(duì)瀏覽器做任何適配,僅僅使用了 jQuery的事件監(jiān)聽(tīng):

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

由于實(shí)現(xiàn)是控件化的,所以定義了一個(gè)私有方法 _keyDownHandler 來(lái)響應(yīng)鍵盤(pán)的動(dòng)作。

3. 按鍵事件甄別

jQuery事件監(jiān)聽(tīng)器返回的事件對(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è)類(lèi)似于查找表的對(duì)象,里面存儲(chǔ)了 ctrl、shift、alt按鈕的各種類(lèi)型組合,每種組合下又分別按照按鍵碼存儲(chǔ)一個(gè)自定義事件類(lèi)型字符串,事件發(fā)生之后會(huì)從這里返回這個(gè)字符串,當(dāng)然,沒(méi)有對(duì)應(yīng)自定義事件的時(shí)候,就老老實(shí)實(shí)地返回空字符串。

4. 事件分發(fā)

_keyCodeProcess 方法從事件中提取出了事件類(lèi)型,我們提前將監(jiān)聽(tīng)的回調(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è)“訂閱”接口,讓開(kāi)發(fā)者可以方便地把自己的回調(diào)函數(shù)存儲(chǔ)到對(duì)象實(shí)例中去,為此,我定義了一個(gè) .bind接口:

function bind(type, callback, description){
    var allType = this.allEventType;
    if(allType.indexOf(type) === -1){
      throwError('不支持改事件類(lèi)型,請(qǐng)先擴(kuò)展該類(lèi)型,或采用其他事件類(lèi)型');
    }
    if(!(callback instanceof Function)){
      throwError('綁定的事件處理回調(diào)必須是函數(shù)類(lèi)型');
    }
    this.callback['on' + type] = callback;
    this.eventDiscibeSet[type] = description || '沒(méi)有該事件的描述';
    return this;
  };

由于是給人用的,所以順帶做了下類(lèi)型檢查。

根據(jù)接口的“對(duì)稱性”,有訂閱最好也有解除訂閱,因此定義了 .unbind接口,只有一句代碼,實(shí)現(xiàn)如下:

function unbind(type){
    this.callback['on' + type] = this._emptyEventHandler;
    return this;
  };

6.擴(kuò)展自定義事件類(lèi)型

鍵盤(pán)事件的組合豐富多彩,如果全部?jī)?nèi)置在控件中的話,會(huì)是很臃腫的,因此除了少數(shù)幾個(gè)常見(jiàn)的組合鍵之外,開(kāi)發(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)寫(xiě)入自定義鍵盤(pán)事件的方法:

_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è)鍵盤(pán)事件監(jiān)聽(tīng)控件就大功告成了,下面是完整實(shí)現(xiàn)代碼:

/**
 * @constructor 鍵盤(pán)事件監(jiān)聽(tīng)器
 * */
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 初始化所有初始自定義事件類(lèi)型
   * */
  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)建的鍵盤(pán)事件類(lè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 自定義鍵盤(pán)事件分發(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 自定義鍵盤(pán)事件
   * @param {Object} config 鍵盤(pán)事件配置方案
   * @param {String} config.type 自定義事件類(lèi)型
   * @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ò)展鍵盤(pán)事件類(lèi)型
   * @param {Object|Array<object>} config 鍵盤(pán)事件配置方案
   * @param {String} config.type 自定義事件類(lèi)型
   * @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 綁定自定義的鍵盤(pán)事件
   * @param {String} type 事件類(lèi)型 如:['up', 'down', 'left', 'right', 'undo', 'redo', 'delete', zoomIn, 'zoomOut']
   * @param {Function} callback 回調(diào)函數(shù),參數(shù)為一個(gè)自定義的仿事件對(duì)象
   * @param {String} description 對(duì)綁定事件的用途進(jìn)行說(shuō)明
   * */
  KeyboardListener.prototype.bind = function bind(type, callback, description){
    var allType = this.allEventType;
    if(allType.indexOf(type) === -1){
      throwError('不支持改事件類(lèi)型,請(qǐng)先擴(kuò)展該類(lèi)型,或采用其他事件類(lèi)型');
    }
    if(!(callback instanceof Function)){
      throwError('綁定的事件處理回調(diào)必須是函數(shù)類(lèi)型');
    }
    this.callback['on' + type] = callback;
    this.eventDiscibeSet[type] = description || '沒(méi)有該事件的描述';
    return this;
  };
  /**
   * @method unbind 解除事件綁定
   * @param {String} type 事件類(lèi)型
   * */
  KeyboardListener.prototype.unbind = function unbind(type){
    this.callback['on' + type] = this._emptyEventHandler;
    return this;
  };
}();

關(guān)于使用jQuery怎么實(shí)現(xiàn)一個(gè)鍵盤(pán)事件監(jiān)聽(tīng)控件就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI