您的位置:首页 > Web前端 > JavaScript

ExtJs源码分析与学习—ExtJs事件机制(五)

2011-07-27 23:37 579 查看
最近一直忙着做产品,所以好久没有写文章了,下面接着把ExtJs事件机制最后一点内容写完。主要是介绍Ext提供的三个辅助实现事件类——快捷键、导航键和鼠标按键事件。

快捷键 Ext.KeyMap

该功能的实现被封装在类Ext.KeyMap中

Js代码


Ext.KeyMap = function(el, config, eventName){

this.el = Ext.get(el);

this.eventName = eventName || "keydown";

this.bindings = [];

if(config){

this.addBinding(config);

}

this.enable();

};

该类实现分为三步,首先找到注册快捷键的元素el,然后把config参数转换为事件的监听函数this.addBinding(config),最后再注册该监听函数this.enable()。先看addBinding方法的实现

Js代码


addBinding : function(config){

if(Ext.isArray(config)){

Ext.each(config, function(c){

this.addBinding(c);

}, this);

return;

}

var keyCode = config.key,

fn = config.fn || config.handler,

scope = config.scope;

if (config.stopEvent) {

this.stopEvent = config.stopEvent;

}

if(typeof keyCode == "string"){

var ks = [];

var keyString = keyCode.toUpperCase();

for(var j = 0, len = keyString.length; j < len; j++){

ks.push(keyString.charCodeAt(j));

}

keyCode = ks;

}

var keyArray = Ext.isArray(keyCode);

//代理按键的监听处理函数,对配置对象中的fn/handle函数进行代理加工处理

var handler = function(e){

//如果指定'shift', 'ctrl', 'alt',而事件对象没有按下指定的'shift', 'ctrl', 'alt',那么就不进行处理

if(this.checkModifiers(config, e)){

var k = e.getKey();

if(keyArray){

for(var i = 0, len = keyCode.length; i < len; i++){

if(keyCode[i] == k){

if(this.stopEvent){

e.stopEvent();

}

fn.call(scope || window, k, e);

return;

}

}

}else{

if(k == keyCode){

if(this.stopEvent){

e.stopEvent();

}

fn.call(scope || window, k, e);

}

}

}

};

this.bindings.push(handler);

},

config配置项支持以下属性

属性 类型 描述

---------- --------------- ----------------------------------------------------------------------

key String/Array 进行处理的单个keycode或keycodes组成的数组

shift Boolean True:只有shift按下的的同时处理key (默认false)

ctrl Boolean True:只有ctrl按下的的同时处理key (默认false)

handler Function 当KeyMap找到预期的组合键时所执行的函数

alt Boolean True:只有alt按下的的同时处理key (默认false)

fn Function 当组合键按下后回调函数

scope Object 回调函数的作用域

stopEvent Boolean 用来停止事件冒泡,阻止元素默认行为。

再看enable方法,把事件注册到元素上

Js代码


enable: function(){

if(!this.enabled){

this.el.on(this.eventName, this.handleKeyDown, this);

this.enabled = true;

}

},

为指定的el元素注册事件

例子:常用复制、剪切、粘贴的实现

Js代码


var config = [{//剪切

key : 'x',

ctrl : true,

fn : function() {

//cut

},

scope : this

},{//复制

key : 'c',

ctrl : true,

fn : function() {

//copy

},

scope : this

},{//粘贴

key : 'v',

ctrl : true,

fn : function() {

//paste

},

scope : this

},{//编辑

key : 'abcdefghigklmnopqrstuvwxyz0123456789',

ctrl : false,

shift : false,

alt : false,

fn : function(k, e) {

alert(k);

},

scope : this

}];

var map = new Ext.KeyMap("my-element", config);

导航键 Ext.KeyNav

导航键的实现被封装在类Ext.KeyNav中,首先看其构造函数

Js代码


Ext.KeyNav = function(el, config){

this.el = Ext.get(el);

Ext.apply(this, config);

if(!this.disabled){//如果被禁用则激活

this.disabled = true;

this.enable();//注册监听函数

}

};

再看注册监听函数

Js代码


enable: function() {

if (this.disabled) {

if (Ext.isSafari2) {

// call stopKeyUp() on "keyup" event

this.el.on('keyup', this.stopKeyUp, this);

}

this.el.on(this.isKeydown()? 'keydown' : 'keypress', this.relay, this);

this.disabled = false;

}

},

IE及其他一些浏览器的keyPress事件不会对非字母数字键进行冒泡,所以采用keyDown事件替代keyPress事件。而该事件的处理函数relay起了代理作用

Js代码


relay : function(e){

var k = e.getKey(),

h = this.keyToHandler[k];

if(h && this[h]){

if(this.doRelay(e, this[h], h) !== true){

e[this.defaultEventAction]();

}

}

},

KeyToHandler是键名和键值对应的hash表,通过event对象获得了键值之后,再和Ext.KeyNav类中12个导航键名比较,看看其是否为导航键,如果是,再看看有没有注册的处理函数,有才运行该监听函数。

该导航键共提供了12个,分别为

keyToHandler : {

37 : "left",

39 : "right",

38 : "up",

40 : "down",

33 : "pageUp",

34 : "pageDown",

46 : "del",

36 : "home",

35 : "end",

13 : "enter",

27 : "esc",

9 : "tab"

},

例子

Js代码


var nav = new Ext.KeyNav("my-element", {

"left" : function(e){

this.moveLeft(e.ctrlKey);

},

"right" : function(e){

this.moveRight(e.ctrlKey);

},

"enter" : function(e){

this.save();

},

scope : this

});

鼠标按住事件 Ext.util.ClickRepeater

鼠标按住事件就是用鼠标按住某个元素,会根据指定的时间间隔来反复地执行同样的动作。该功能的实现被封装在类Ext.util.ClickRepeater,首先看构造函数

Js代码


constructor : function(el, config){

this.el = Ext.get(el);

this.el.unselectable();//元素内容不能选择

Ext.apply(this, config);

this.addEvents(

/**

* @event mousedown

* 当鼠标按下的时候触发。

* Fires when the mouse button is depressed.

* @param {Ext.util.ClickRepeater} this

* @param {Ext.EventObject} e

*/

"mousedown",

/**

* @event click

* 当元素被按下接受到按下的消息的时候出发,比mousedown事件慢。

* Fires on a specified interval during the time the element is pressed.

* @param {Ext.util.ClickRepeater} this

* @param {Ext.EventObject} e

*/

"click",

/**

* @event mouseup

* 当鼠标释放后触发。

* Fires when the mouse key is released.

* @param {Ext.util.ClickRepeater} this

* @param {Ext.EventObject} e

*/

"mouseup"

);

if(!this.disabled){

this.disabled = true;

this.enable();

}

// allow inline handler

if(this.handler){

this.on("click", this.handler, this.scope || this);

}

Ext.util.ClickRepeater.superclass.constructor.call(this);

},

该构造函数中调用了this.enable();来处理鼠标按下事件,然后如果配置项声明了handler处理函数,会把该函数注册到cilck事件中。下面看方法enable

Js代码


enable: function(){

if(this.disabled){

this.el.on('mousedown', this.handleMouseDown, this);

if (Ext.isIE){

this.el.on('dblclick', this.handleDblClick, this);

}

if(this.preventDefault || this.stopDefault){

this.el.on('click', this.eventOptions, this);

}

}

this.disabled = false;

},

该方法中给元素el注册了mousedown事件,如果是IE浏览器,还注册了dblclick事件,然后根据配置项来阻止默认或冒泡处理,下面看handleMouseDown

Js代码


handleMouseDown : function(e){

clearTimeout(this.timer);

this.el.blur();//除去焦点

if(this.pressClass){

this.el.addClass(this.pressClass);

}

this.mousedownTime = new Date();

Ext.getDoc().on("mouseup", this.handleMouseUp, this);

this.el.on("mouseout", this.handleMouseOut, this);

this.fireEvent("mousedown", this, e);

this.fireEvent("click", this, e);

// Do not honor delay or interval if acceleration wanted.

if (this.accelerate) {

this.delay = 400;

}

this.timer = this.click.defer(this.delay || this.interval, this, [e]);

},

当用户在某个元素上按下鼠标时,首先让该元素失去焦点,改变样式,同时还分别为鼠标按键松开或移出注册了监听函数,最后按指定的间隔来推迟运行click函数

Js代码


click : function(e){

this.fireEvent("click", this, e);

this.timer = this.click.defer(this.accelerate ?

this.easeOutExpo(this.mousedownTime.getElapsed(),

400,

-390,

12000) :

this.interval, this, [e]);

},

该函数递归调用click函数,如果设置了this.accelerate,时间间隔就会按一定的算法越运行越短,即运行click会越来越快。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: