亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

基于 jQuery 實現鍵盤事件監聽控件

2019-11-19 11:52:41
字體:
來源:轉載
供稿:網友

最近項目里要做一個畫板,需要對鍵盤事件進行監聽,來進行諸如撤回、重做、移動、縮放等操作,因此順手實現了一個鍵盤事件監聽控件,期間略有收獲,整理出來,希望對大家有所幫助,更希望能獲得高手的指點。

1. 自動獲取焦點

似乎瀏覽器的鍵盤事件只能被那些可以獲得焦點的元素設置監聽,而通常需要監聽事件的 <DIV>、<CANVAS> 元素都不能獲得焦點,因此需要修改目標元素的某些屬性使其可以獲得焦點,另外一種可行的方法是將事件委托給諸如 <INPUT> 標簽。這里采用的是第一類方法,當然,可以修改的屬性也不止一種,例如,對于 <DIV> 標簽可以將其 “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<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;  };}();

總結

以上所述是小編給大家介紹的基于 jQuery 實現鍵盤事件監聽控件,希望對大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會及時回復大家的!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产a∨精品一区二区三区不卡| 国产一区二区三区在线看| 欧美xxxx18性欧美| 夜夜嗨av色综合久久久综合网| 成人精品视频99在线观看免费| 欧美激情亚洲综合一区| 欧美高清视频免费观看| 综合激情国产一区| 国产成人在线播放| 日韩av一区在线观看| 久久精品国产亚洲精品2020| 亚洲视频999| 欧美一级免费看| 91中文字幕在线观看| 久久久精品一区二区| 成人在线播放av| 色av中文字幕一区| 欧美成年人视频网站欧美| 成人国产精品av| 亚洲国产美女久久久久| 国内精品美女av在线播放| 亚洲国产成人精品一区二区| 日韩美女视频免费看| 亚洲影院高清在线| 日韩av在线资源| 亚洲国产欧美一区二区丝袜黑人| 国产一区玩具在线观看| 国产一区二区成人| 成人国产亚洲精品a区天堂华泰| 久久亚洲国产精品| 久久精品视频中文字幕| 日韩亚洲精品电影| 国产a级全部精品| 国产一区二区日韩精品欧美精品| 中文字幕精品网| 91精品国产色综合久久不卡98| 日韩av中文字幕在线| 色综合色综合久久综合频道88| 日韩精品极品在线观看播放免费视频| 亚洲国产精品悠悠久久琪琪| 成人国产精品色哟哟| 麻豆国产精品va在线观看不卡| 日本亚洲精品在线观看| 亚洲国产成人久久综合| 日韩亚洲成人av在线| 精品久久久久久国产91| 国产精品视频久久| 国产视频亚洲视频| 久久天天躁夜夜躁狠狠躁2022| 欧美日韩xxx| 中文字幕精品www乱入免费视频| 在线视频一区二区| 91精品国产综合久久香蕉| 亚洲午夜av电影| 欧美激情2020午夜免费观看| 国产精品一区二区三区久久久| 亚洲娇小xxxx欧美娇小| 欧美国产日韩一区二区三区| 欧美激情一区二区三区成人| 久久人人爽人人爽爽久久| 在线丨暗呦小u女国产精品| 亚洲福利视频免费观看| 亚洲福利视频二区| 国产91亚洲精品| 亚洲高清免费观看高清完整版| 国内精品模特av私拍在线观看| 午夜精品美女自拍福到在线| 国产精品jvid在线观看蜜臀| 日韩电影免费观看在线观看| 久久精品99无色码中文字幕| 亚洲区中文字幕| 亚洲精品国产成人| 少妇高潮久久久久久潘金莲| 亚洲精品美女视频| 亚洲天堂第二页| 亚洲精品久久久久久久久久久久| 国产精自产拍久久久久久蜜| 国产日韩欧美成人| 亚洲综合最新在线| 国产精品高精视频免费| 成人福利在线观看| 中文字幕亚洲第一| 国产精品久久久av久久久| 日本一本a高清免费不卡| 欧美中文在线观看| 成人一区二区电影| 国产精品久久久一区| 久久精视频免费在线久久完整在线看| 91色在线观看| 久久精品福利视频| 久久躁狠狠躁夜夜爽| 久久久久久97| 日韩av在线资源| 国产精品白丝av嫩草影院| 日韩av网址在线| 亚洲人成伊人成综合网久久久| 播播国产欧美激情| 精品福利一区二区| 国产成人精品免费视频| 5278欧美一区二区三区| 午夜精品视频在线| 狠狠躁夜夜躁人人爽天天天天97| 92国产精品久久久久首页| 美女视频久久黄| 亚洲视频电影图片偷拍一区| 亚洲精品成人久久| 欧美性做爰毛片| 日韩中文字幕网| 国语自产精品视频在线看一大j8| 久久久久久久久亚洲| 国内成人精品视频| 爱福利视频一区| 色无极影院亚洲| 日韩视频永久免费观看| 亚洲日本aⅴ片在线观看香蕉| 2019中文字幕在线免费观看| 欧美理论电影网| 久久久久久久激情视频| 午夜精品蜜臀一区二区三区免费| 97国产精品视频人人做人人爱| 久久久成人av| 日韩av电影免费观看高清| 日韩中文综合网| 国产精品高清在线| 久久亚洲私人国产精品va| 欧美一级视频在线观看| 18一19gay欧美视频网站| 欧美天天综合色影久久精品| 国产欧美亚洲视频| 国产精品久久久久久久久久ktv| 欧美国产视频一区二区| 欧美精品福利视频| 日韩av网站大全| 狠狠干狠狠久久| 一区二区三区无码高清视频| 日本一区二三区好的精华液| 欧美激情综合色综合啪啪五月| 91九色国产社区在线观看| 欧美激情伊人电影| 亚洲日本成人网| 欧美麻豆久久久久久中文| 欧美体内谢she精2性欧美| 亚洲毛片在线观看| 久久亚洲精品中文字幕冲田杏梨| 成人黄色中文字幕| 久久久久久高潮国产精品视| 美女性感视频久久久| 欧美日韩国产综合视频在线观看中文| 91极品视频在线| 国产精品福利网| 亚洲精品成a人在线观看| 亚洲无限乱码一二三四麻| 久久久人成影片一区二区三区观看| 久久精品国产亚洲精品| 中文一区二区视频| 国产91热爆ts人妖在线| 91久久精品美女高潮| 欧美激情亚洲激情| 国产午夜精品一区二区三区| 91tv亚洲精品香蕉国产一区7ujn| 日本精品久久中文字幕佐佐木| 久久精品国产v日韩v亚洲| 欧美性xxxx极品hd满灌| 日韩精品在线观|