由于Ext2.0中所有的组件都是由Observable继承而来,理解Ext就需要先从Ext.util.Observable说起,而Observable是对Event对象进行管理,从而理解Observable必须首先从Ext.util.Event说起。
Ext.util.Event是一个封装的非常精致的对象,但和你想象的不同,Event同任何的HTML DOM元素没有任何的关系(尽管Ext是处理HTML元素的),实际上,它是一个通用的事件及其事件的处理的对象。 也许有朋友要问,HTML Element本身已经支持了事件,为什么还要再重新设计一套Event机制呢?其实,基本上所有的javascript框架都会实现自己的Event机制,原因很多,但是至少有一点:HTML元素对于事件的处理是通过简单的单一绑定实现,也就是说,如果不进行任何的封装,你的事件只能唯一的绑定到一个事件处理句柄,举个例子:
var e=document.getElementById("test"); e.onclick=function(){alert("handle1")}; e.onclick=function(){alert("handle2")};
运行的结果你回发现,只会弹出一个"handle2"的alert框,因为第一个事件已经被第二个事件重载了。而使用Ext框架,你可以放心的解决这个问题,同一个事件可以依次被绑定到多个事件处理句柄上。
Ext.util.Event对象构建器需要传入两个对象:obj(处理事件的缺省对象),name(事件名称)。在构建Event对象时,Event对象会同时构建一个事件的处理函数的数组:listeners,通过这个数组实现了一个事件的多个事件句柄函数的处理。
handler,listeners区别
handler:
handler与Action相关联,一个Action可以有多个Component引用;
Action是一个可被共享的对象,有五个主要的属性:text, handler, iconCls, disabled, hidden
component的构建方式比较有意思:
new Ext.Button(action)
是Button接收一个Action对象作为构造参数吗?但是查看Button的API却没有发现action属性。反而Button的构造参数是 一个(Object config),也就是说,只是一个配置对象(包含各种属性),而Action的五个属性正好Button也都有,所以,可以接收一个Action来进行 构造。
其他属性不考虑,看handler,Button中的handler配置项文档说明,这个handler是与click Event关联的。也就是说,click是Button这个Component的首要Event(参考Action中handler的文档),这就是 Handler的运行方式:被某个组件的首要Event触发。
var bt = new Ext.Button({ renderTo: Ext.get("di"), text: "事件实现1", allowDepress: true, //是否允许按钮被按下的状态 enableToggle: true, //是否允许按钮在弹起和按下两种状态中切换 // handler: function () { // Ext.Msg.alert("提示", "handler"); // }, // listeners: { "click": function () { // Ext.Msg.alert("提示", "listeners"); // }, "click": function () { // Ext.Msg.alert("提示", "listeners2"); // }, //// "mouseover": function () { //// Ext.Msg.alert("提示", "mouseover1"); //// } // }, id: "bt1" }); function funOn(){ Ext.Msg.alert("提示", "on"); } function funAddListener(){ Ext.Msg.alert("提示", "addListener"); } bt.on("click", funOn()); // bt.addListener("click",function(){ // Ext.Msg.alert("提示", "addListenefdsr"); // }); bt.addListener("click",funAddListener()); // bt.on("mouseover", function () { // Ext.Msg.alert("提示", "mouseenter2"); // }); // bt.un("click",function(){});
多个首事件时最后触发的一定是handler
handler只能覆盖首事件的操作。
没有handler时,同类事件的方法触发最后的一个。
bug,用on,addListener调用已存在的方法时会自动调用。
listeners:
为了能够在同一事件中添加多个操作,在不同的浏览器中有不同的方法
var btn = document.getElementById("Button1"); if (window.addEventListener) { btn.addEventListener("click", function () { alert("hongda1"); }, false); } else if (window.attachEvent) { //ie btn.attachEvent("onclick", function () { alert("hongda2"); }); }
在不同的浏览器中任何一个事件都有相对应的数组来存储对应的多个操作,在Ext中为了方便,就表示为listeners.
估计在一个页面中按事件的不同划分不同的listeners,例如:unloadlisteners
这些listeners大概是个key,value的对象,key为元素的id,取value为listeners[el.id],unload的就为unloadlisteners[el.id]
这个value是一个数组对象,里面存储着该元素该事件的多个操作。
/** * 删除 el 事件 */ removeListener: function(el, eventName, fn) { el = Ext.getDom(el); var i, len, li, lis; if (el && fn) { if(eventName == UNLOAD){ if((lis = unloadListeners[el.id]) !== undefined){ for(i = 0, len = lis.length; i < len; i++){ if((li = lis[i]) && li[TYPE] == eventName && li[FN] == fn){ unloadListeners[el.id].splice(i, 1); } } } return; } doRemove(el, eventName, fn, false); } }, /** * 返回一个符合当前浏览器的函数用来注销事件, 对于非ie下的浏览器也让其可以支持mouseleave/mouseenter */ doRemove = function(){ var ret; if (win.removeEventListener) { ret = function (el, eventName, fn, capture) { if (eventName == 'mouseenter') { eventName = MOUSEOVER; } else if (eventName == 'mouseleave') { eventName = MOUSEOUT; } el.removeEventListener(eventName, fn, (capture)); }; } else if (win.detachEvent) { ret = function (el, eventName, fn) { el.detachEvent("on" + eventName, fn); }; } else { ret = function(){}; } return ret; }();
addListener: function(el, eventName, fn) { el = Ext.getDom(el); if (el && fn) { if (eventName == UNLOAD) { if (unloadListeners[el.id] === undefined) { unloadListeners[el.id] = []; } unloadListeners[el.id].push([eventName, fn]); return fn; } return doAdd(el, eventName, fn, false); } return false; }, doAdd = function() { var ret; if (win.addEventListener) {//标准浏览器 ret = function(el, eventName, fn, capture) { if (eventName == 'mouseenter') { fn = fn.createInterceptor(checkRelatedTarget); el.addEventListener(MOUSEOVER, fn, (capture)); } else if (eventName == 'mouseleave') { fn = fn.createInterceptor(checkRelatedTarget); el.addEventListener(MOUSEOUT, fn, (capture)); } else { el.addEventListener(eventName, fn, (capture)); } return fn; }; } else if (win.attachEvent) {//ie浏览器,ie9中会同时支持这两种方式win.attachEvent和win.addEventListener, ret = function(el, eventName, fn, capture) { el.attachEvent("on" + eventName, fn); return fn; }; } else { ret = function(){}; } return ret; }(), function checkRelatedTarget(e) { return !elContains(e.currentTarget, pub.getRelatedTarget(e)); } //判断某个元素child是否是parent的子元素,是则返回true,否则false。 function elContains(parent, child) { if(parent && parent.firstChild){ while(child) { if(child === parent) { return true; } child = child.parentNode; //nodeType 属性返回被选节点的节点类型。等于1为节点Element,当child不是parent的孩子节点时,会一直执行,直到child.nodeType 为 9 document时 if(child && (child.nodeType != 1)) { child = null; } } } return false; } getRelatedTarget : function(ev) { ev = ev.browserEvent || ev; return this.resolveTextNode(ev.relatedTarget || (/(mouseout|mouseleave)/.test(ev.type) ? ev.toElement : /(mouseover|mouseenter)/.test(ev.type) ? ev.fromElement : null)); },
ExtJs 事件
自定义事件
Person = function(name){ this.name = name; this.sayNum = 0; this.say = function(){ if(this.sayNum < 2){ this.sayNum += 1; alert('I am '+name); }else{ this.fireEvent('onSay',this);//激发自定义事件 } } this.addEvents({//加入自定义事件 "onSay" : true }); } Ext.extend(Person, Ext.util.Observable);//继承自Ext.util.Observable var per = new Person('tom');//创建对象 per.addListener('onSay',handler);//为自定义事件绑定处理函数 function handler(){//事件处理函数 alert('发生了自定义事件'); } Person = function(name){ this.name = name; this.say = function(){ this.fireEvent('onSay',this.name);//激发自定义事件 } this.addEvents({//加入自定义事件 "onSay" : true }); } Ext.extend(Person, Ext.util.Observable);//继承自Ext.util.Observable var per = new Person('tom');//创建对象 per.addListener('onSay',handler);//为自定义事件绑定处理函数 function handler(name){//事件处理函数 alert("I'am " + name); }
事件拦截器
Person = function(name){ this.name = name; this.say = function(){ this.fireEvent('onSay',this);//激发自定义事件 } this.addEvents({//加入自定义事件 "onSay" : true }); } Ext.extend(Person, Ext.util.Observable);//继承自Ext.util.Observable var per = new Person('tom');//创建对象 per.addListener('onSay',handler);//为自定义事件绑定处理函数 function handler(){//事件处理函数 alert('发生了自定义事件'); } //为per对象添加拦截器 Ext.util.Observable.capture(per,captureFunction); //拦截函数 function captureFunction(eventName){ if(eventName == 'onSay'){//事件名称是onSay则返回false终止事件的执行 alert("拦截事件“"+eventName+"”的执行。"); return false; } return true; }
Ext.EventObject
function handleClick(e){ // e它不是一个标准的事件对象,而是Ext.EventObject。 Ext.EventObject e.preventDefault(); var target = e.getTarget(); ... } var myDiv = Ext.get("myDiv"); myDiv.on("click", handleClick); // 或者or Ext.EventManager.on("myDiv", 'click', handleClick); Ext.EventManager.addListener("myDiv", 'click', handleClick);
Ext.EventManager
Ext.onReady(function(){ Ext.EventManager.addListener('btn','click',handler);//绑定处理函数 function handler(){//事件处理函数 alert('hello'); } });
http://www.cnblogs.com/meetrice/archive/2008/05/23/1206102.html
http://linder0209.iteye.com/blog/963466
http://blog.csdn.net/homsky/article/details/5451072