转自: 风域,再次感谢
Ext中的事件机制是在 Ext.util.Observable 中定义的,举一个例子来说明事件机制,先看一下代码,然后慢慢说
person.js
Ext.namespace("com.meizhi");
/* 定义NameSpace的别名 */
Mz = com.meizhi;
Mz.Person = function() {
/* 定义事件 */
this.addEvents(
"nameChange",
"sexChange"
);
};
Ext.extend(Mz.Person, Ext.util.Observable, {
name:"",
sex:"",
setName:function(_name){
if(this.name != _name) {
/* 发布事件 */
this.fireEvent("nameChange", this, this.name, _name);
this.name = _name;
}
},
setSex:function(_sex){
if(this.sex != _sex){
/* 发布事件 */
this.fireEvent("sexChange", this, this.sex, _sex);
this.sex = _sex;
}
}
});
看JS文件中的定义
- 先定义了一个Person类,在类中只有一个属性addEvents,属性值是一个字符串数组,在这里是定义了两个 Event 事件的名字。
- 声明 Person 类继承自 Ext.util.Observable 类,并且定义了Person类的另外一些属性:name,sex,以及它们的写方法(这里把setName和setSex称为属性更合适一些)。
- 在属性的写方法 setName ,setSex 中,如果传入的值和实例化的 Person 对象的属性值不一致就会调用相应的事件,并且给属性赋值。
- 这样 Person 类的属性定义就完成了,并且现在 Person 是具有Ext事件机制的类,以后在 Person 类的实例中绑定和调用事件就非常方便了。
Ext.util.Observable 维护了一个events 对象的数组,并提供了更加方便的对于事件的封装和调用机制。(参考:http://www.cnblogs.com/meetrice/archive/2008/05/23/1206108.html )
addEvents():绑定事件,看一下它的源代码
addEvents : function(o){
if(!this.events){
this.events = {};
}
if(typeof o == 'string'){
for(var i = 0, a = arguments, v; v = a[i]; i++){
if(!this.events[a[i]]){
// 将传入的事件名称注册到事件列表中
this.events[a[i]] = true;
}
}
}else{
Ext.applyIf(this.events, o);
}
}
该方法实际上就是在 Person 对象上绑定了两个没有任何实现的事件名 ,这样 Person 对象就具有了两个空的Event对象(绑定可以执行操作的Event对象使用 addlistener 方法)。
fireEvent():发布事件,也就是触发绑定的事件。源代码中的定义
fireEvent : function(){
if(this.eventsSuspended !== true){
//通过addEvents()注册的事件会被封装成events对象
var ce = this.events[arguments[0].toLowerCase()];
if(typeof ce == "object"){
//触发事件对象
return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
}
}
return true;
}
现在Person类的结构就很清楚了,
- name属性
- sex属性
- setName属性(如果传入参数和name属性不一致,调用 “nameChange” 事件)
- setSex属性(如果传入参数和name属性不一致,调用 “sexChange” 事件)
在person.js中完成是事件的定义和发布,那事件是在什么时候被订阅的呢? 事件触发之后又要进行哪些操作呢?
person.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Event</title>
<link type="text/css" rel="stylesheet" href="../../ext/resources/css/ext-all.css">
<script type="text/javascript" src="../../ext/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../../ext/ext-all.js"></script>
<script type="text/javascript" src="person.js"></script>
<script type="text/javascript">
var _person = null;
button_click = function() {
_person.setName(prompt("请输入姓名", ""));
_person.setSex(prompt("请输入性别", ""));
}
Ext.onReady(function(){
var txt_name = Ext.get("txt_name");
var txt_sex = Ext.get("txt_sex");
/* 构建Person类 */
_person = new Mz.Person();
/* 订阅事件 */
_person.on("nameChange",
function(_person, _old, _new){
txt_name.dom.value = _new;
});
/* 订阅事件 */
_person.on("sexChange",
function(_person, _old, _new){
txt_sex.dom.value = _new;
});
/* 订阅事件 */
_person.on("nameChange",
function(_person, _old, _new){
document.title = _new;
});
});
</script>
</head>
<body>
姓名:<input type="text" id="txt_name" maxlength="10" /><br/>
性别:<input type="text" id="txt_sex" maxlength="10" /><br/>
<input type="button" value="输入" οnclick="button_click()"/>
</body>
</html>
HTML文件页面中定义了两个输入框,和一个按钮,通过Ext.onReady(),页面初始化后首先执行里面的代码
- Ext.get()取得文本框中的值
- 构造 Person 类实例
- 订阅事件,这个时候定义 Person 中的设值属性的操作具体执行的内容,给setName()和setSex()订阅的事件中添加内容,这一点非常灵活,我们一开始只要先定义一个事件,而这个事件只有一个名字,没有具体实现,我们在订阅这个事件的时候才告诉它如果事件发生我们需要进行什么样的操作。
在点击按钮的时候,调用 button_click 方法来给 person 实例属性赋值。
在订阅事件的时候,用到的是 Observable.on 方法,实际上它是 Observable.addListener 的缩写(Ext里面的缩写好多啊...),源代码中是这样定义的
Ext.util.Observable.prototype.on = Ext.util.Observable.prototype.addListener;
绑定事件真正起作用的方法就是addListener()方法,源码中的定义
addListener : function(fn, scope, options){
scope = scope || this.obj;
if(!this.isListening(fn, scope)){
var l = this.createListener(fn, scope, options);
if(!this.firing){
this.listeners.push(l);
}else{ // if we are currently firing this event, don't disturb the listener loop
this.listeners = this.listeners.slice(0);
this.listeners.push(l);
}
}
}