ExtJS中的KeyNav和KeyMap是两个用来处理键盘事件的类,它们默认的工作模式都是屏蔽了浏览器的默认事件和事件起泡的。即如下的默认配置。
KeyMap: stopEvent: true,
KeyNav: defaultEventAction: stopEvent,
所以当我们有两层或者三层的包容元素需要使用相同的键盘键相应事件时,就会发生,内层元素屏蔽了外层包容元素的事件响应,究其原因,就是ExtJS阻止了事件起泡至外层的包容元素。
本例当中,使用相同的键盘键“Key Down”来分别响应TabPanel的tab切换,FormPanel的焦点切换,ComboBox的选项选择。使用键盘键"Enter"进行三种模式之间的切换。
程序运行结果如下:
程序代码如下
<html> <head> <title>Event Conflict Solve</title> <link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css"/> <script type="text/javascript" src="../../adapter/ext/ext-base.js"></script> <script type="text/javascript" src="../../ext-all-debug.js"></script> <script type="text/javascript"> Ext.namespace('Ext.exampledata'); Ext.exampledata.states = [ ['AL', 'Alabama', 'The Heart of Dixie'], ['AK', 'Alaska', 'The Land of the Midnight Sun'], ['AZ', 'Arizona', 'The Grand Canyon State'], ['AR', 'Arkansas', 'The Natural State'], ['CA', 'California', 'The Golden State'], ['CO', 'Colorado', 'The Mountain State'], ['CT', 'Connecticut', 'The Constitution State'], ['DE', 'Delaware', 'The First State'], ['DC', 'District of Columbia', "The Nation's Capital"] ]; /* * Avoid event conflict bettween contained elements and containg element. * TODO: Add a tips for which mode we are working at * (try to use a property change event to fulfill this fuctionality?). */ Ext.onReady(function(){ MyCombox = Ext.extend(Ext.form.ComboBox, { initEvents : function(){ Ext.form.ComboBox.superclass.initEvents.call(this); this.keyNav = new Ext.KeyNav(this.el, { "up" : function(e){ if (MOVE_MODE != MOVE_MODE_COMB) { return; } this.selectPrev(); e.stopPropagation(); }, "down" : function(e){ if (MOVE_MODE != MOVE_MODE_COMB) { return; } this.selectNext(); e.stopPropagation(); }, "enter" : function(e){ if(!this.isExpanded()){ this.onTriggerClick(); MOVE_MODE = MOVE_MODE_COMB; } else { this.onViewClick(); MOVE_MODE = MOVE_MODE_FORMS; } e.stopPropagation(); }, scope : this, forceKeyDown : true, defaultEventAction: 'preventDefault' }); this.queryDelay = Math.max(this.queryDelay || 10, this.mode == 'local' ? 10 : 250); this.dqTask = new Ext.util.DelayedTask(this.initQuery, this); if(this.typeAhead){ this.taTask = new Ext.util.DelayedTask(this.onTypeAhead, this); } if(!this.enableKeyEvents){ this.mon(this.el, 'keyup', this.onKeyUp, this); } } }); Ext.reg("myComb", MyCombox); var store = new Ext.data.ArrayStore({ fields: ['abbr', 'state', 'nick'], data : Ext.exampledata.states // from states.js }); var activeTabIndex = 0; var formFieldFocusIndex = 0; var MOVE_MODE_TABS = 1; var MOVE_MODE_FORMS = 2; var MOVE_MODE_COMB = 3; var MOVE_MODE = MOVE_MODE_TABS; var firstForm = new Ext.form.FormPanel({ border: false, id: 'firstForm', labelAlign: 'right', defaultType: 'textfield', items: [{ id: "txtFirstName", fieldLabel: "First Name", width: 180 }, { fieldLabel: "Last Name", width: 180 }, { fieldLabel: "Gender", width: 180 },{ xtype: "myComb", id: "cmbHobbies", fieldLabel: "Hobbies", editable: false, store: store, displayField:'state', typeAhead: true, mode: 'local', forceSelection: true, triggerAction: 'all', emptyText:'Select a state...', selectOnFocus:true, width: 180 }, { xtype: "checkbox", fieldLabel: "Particpate" }] }); var tabs = new Ext.TabPanel({ renderTo: document.body, activeTab: activeTabIndex, id: 'tabs', width:600, height:250, plain:true, defaults:{autoScroll: true}, items:[{ title: 'FromTab1', items: firstForm },{ title: 'FromTab2', html: "My content was added during construction." },{ title: 'FromTab3', autoLoad:'ajax1.htm' },{ title: 'Ajax Tab 2', autoLoad: {url: 'ajax2.htm', params: 'foo=bar&wtf=1'} },{ title: 'Event Tab', html: "I am tab 4's content. I also have an event listener attached." } ] }); firstForm.items.item(formFieldFocusIndex).focus(); new Ext.KeyMap('firstForm', [ { key: Ext.EventObject.DOWN, handler: function(key, e) { if (MOVE_MODE != MOVE_MODE_FORMS) { return; } formFieldFocusIndex++; if (formFieldFocusIndex >= this.items.getCount()) { formFieldFocusIndex = 0; } this.items.item(formFieldFocusIndex).focus(); e.stopPropagation(); }, scope: firstForm, stopEvent: false }, { key: Ext.EventObject.UP, handler: function(key, e) { if (MOVE_MODE != MOVE_MODE_FORMS) { return; } formFieldFocusIndex--; if (formFieldFocusIndex < 0) { formFieldFocusIndex = this.items.getCount() - 1; } this.items.item(formFieldFocusIndex).focus(); e.stopPropagation(); }, scope: firstForm, stopEvent: false } ]); new Ext.KeyMap('tabs', [ { key: Ext.EventObject.DOWN, handler: function(key, e) { if (MOVE_MODE != MOVE_MODE_TABS) { return; } activeTabIndex++; if (activeTabIndex > this.items.getCount() - 1) { activeTabIndex = 0; } this.setActiveTab(activeTabIndex); }, scope: tabs, stopEvent: true }, { key: Ext.EventObject.UP, handler: function(key, e) { if (MOVE_MODE != MOVE_MODE_TABS) { return; } activeTabIndex--; if (activeTabIndex < 0) { activeTabIndex = this.items.getCount() - 1; } this.setActiveTab(activeTabIndex); }, scope: tabs, stopEvent: true } ]); new Ext.KeyMap(document, [ { key: Ext.EventObject.ENTER, handler: function(key, e) { //var target = null; var activeTab = tabs.getActiveTab(); var curTabElement = null; var curExtCtl = null; for (var i = 0; i < tabs.items.getCount(); i++) { //curTabElement = tabs.items.item(i).el; //var selecter = "DIV[id='" + tabs.items.item(i).id + "']"; //target = e.getTarget(selecter, document.body, true); curTabElement = tabs.items.item(i); if (curTabElement === activeTab) { curExtCtl = tabs.items.item(i); break; } } if (curExtCtl == null) { return; } if (curExtCtl.items.getCount() < 1) { return; } var curExtForm = curExtCtl.items.item(0); if (curExtForm.getXType() == 'form') { if (curExtForm.items.getCount() < 1) { return; } formFieldFocusIndex = 0; curExtForm.items.item(formFieldFocusIndex).setValue(""); curExtForm.items.item(formFieldFocusIndex).focus(); } if (MOVE_MODE == MOVE_MODE_FORMS) { MOVE_MODE = MOVE_MODE_TABS; } else { MOVE_MODE = MOVE_MODE_FORMS; } }, scope: tabs, stopEvent: "preventDefault" } ]); }); </script> </head> </html>