[转帖]Mootools源码分析-17 -- Element-4
原帖地址:http://space.flash8.net/space/?18713/viewspace-403269.html
原作者:我佛山人
//Element事件的setter,addEvents的快捷方式
Element.Properties.events = {set: function(events) {
this.addEvents(events);
}};
//Element、Window 和 Document的事件扩展
Native.implement([Element, Window, Document], {
//添加事件监听,有别于addListener,可以使用自定义事件
addEvent: function(type, fn) {
//取临时对象,注意提供的默认值
var events = this.retrieve('events', {});
//查找指定类型的事件列表
events[type] = events[type] || {'keys': [], 'values': []};
//如果已经添加了该监听
if (events[type].keys.contains(fn)) return this;
//添加到事件订阅列表
events[type].keys.push(fn);
var realType = type, custom = Element.Events.get(type), condition = fn, self = this;
//如果是自定义事件
if (custom) {
//添加自定义事件时的处理
if (custom.onAdd) custom.onAdd.call(this, fn);
//自定义事件的条件
if (custom.condition) {
condition = function(event) {
if (custom.condition.call(this, event)) return fn.call(this, event);
return false;
};
}
realType = custom.base || realType;
}
var defn = function() {
return fn.call(self);
};
//内置事件类型处理
var nativeEvent = Element.NativeEvents[realType] || 0;
//如果是内置的事件
if (nativeEvent) {
//如果是交互事件
if (nativeEvent == 2) {
//闭包
defn = function(event) {
//这样最后传给监听函数的参数是经包装过Event对象
event = new Event(event, self.getWindow());
//这个条件用于扩展内置事件
if (condition.call(self, event) === false) event.stop();
};
}
//最终还是调用addListener
this.addListener(realType, defn);
}
//添加到列表
events[type].values.push(defn);
return this;
},
//移除事件监听
removeEvent: function(type, fn) {
//取临时对象,不提供默认值
var events = this.retrieve('events');
//如果临时对象不存在,说明监听不存在,直接返回
if (!events || !events[type]) return this;
//检查是否已添加本监听
var pos = events[type].keys.indexOf(fn);
//没有则返回
if (pos == -1) return this;
//从队列中移除
var key = events[type].keys.splice(pos, 1)[0];
var value = events[type].values.splice(pos, 1)[0];
//自定义事件处理
var custom = Element.Events.get(type);
//如果是自定义事件
if (custom) {
//自定义事件的移除处理
if (custom.onRemove) custom.onRemove.call(this, fn);
type = custom.base || type;
}
//如果是内置事件还需要调用removeListener来处理
return (Element.NativeEvents[type]) ? this.removeListener(type, value) : this;
},
//批量添加事件监听
addEvents: function(events) {
for (var event in events) this.addEvent(event, events[event]);
return this;
},
//批量移除事件监听
removeEvents: function(type) {
//取临时对象,不提供默认值
var events = this.retrieve('events');
//没有事件监听直接返回
if (!events) return this;
//如果不提供type参数,移除所有类型的事件
if (!type) {
for (var evType in events) this.removeEvents(evType);
events = null;
} else if (events[type]) {
//移除指定类型的事件
while (events[type].keys[0]) this.removeEvent(type, events[type].keys[0]);
events[type] = null;
}
return this;
},
//事件通知
fireEvent: function(type, args, delay) {
//取临时对象,不提供默认值
var events = this.retrieve('events');
//没有事件监听
if (!events || !events[type]) return this;
events[type].keys.each(function(fn) {
//注意事件监听的函数中this默认指向当前Element
fn.create({'bind': this, 'delay': delay, 'arguments': args})();
}, this);
return this;
},
//事件复制
cloneEvents: function(from, type) {
//事件源
from = $(from);
var fevents = from.retrieve('events');
if (!fevents) return this;
//不提供type参数则复制所有事件
if (!type) {
for (var evType in fevents) this.cloneEvents(from, evType);
} else if (fevents[type]) {
//复制指定类型的事件
fevents[type].keys.each(function(fn) {
this.addEvent(type, fn);
}, this);
}
return this;
}
});
//内置事件,分两种类型
Element.NativeEvents = {
click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons
mousewheel: 2, DOMMouseScroll: 2, //mouse wheel
mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement
keydown: 2, keypress: 2, keyup: 2, //keyboard
focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements
load: 1, unload: 1, beforeunload: 1, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window
error: 1, abort: 1, scroll: 1 //misc
};
//就地执行的匿名函数
(function() {
var $check = function(event) {
var related = event.relatedTarget;
if (related == undefined) return true;
if (related === false) return false;
return ($type(this) != 'document' && related != this && related.prefix != 'xul' && !this.hasChild(related));
};
//基于原事件扩展出的自定义事件
Element.Events = new Hash({
//鼠标进入事件
mouseenter: {
base: 'mouseover',
condition: $check
},
//鼠标离开事件
mouseleave: {
base: 'mouseout',
condition: $check
},
//鼠标滚轮事件
mousewheel: {
base: (Browser.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel'
}
});
})();
Element.Properties.events = {set: function(events) {
this.addEvents(events);
}};
//Element、Window 和 Document的事件扩展
Native.implement([Element, Window, Document], {
//添加事件监听,有别于addListener,可以使用自定义事件
addEvent: function(type, fn) {
//取临时对象,注意提供的默认值
var events = this.retrieve('events', {});
//查找指定类型的事件列表
events[type] = events[type] || {'keys': [], 'values': []};
//如果已经添加了该监听
if (events[type].keys.contains(fn)) return this;
//添加到事件订阅列表
events[type].keys.push(fn);
var realType = type, custom = Element.Events.get(type), condition = fn, self = this;
//如果是自定义事件
if (custom) {
//添加自定义事件时的处理
if (custom.onAdd) custom.onAdd.call(this, fn);
//自定义事件的条件
if (custom.condition) {
condition = function(event) {
if (custom.condition.call(this, event)) return fn.call(this, event);
return false;
};
}
realType = custom.base || realType;
}
var defn = function() {
return fn.call(self);
};
//内置事件类型处理
var nativeEvent = Element.NativeEvents[realType] || 0;
//如果是内置的事件
if (nativeEvent) {
//如果是交互事件
if (nativeEvent == 2) {
//闭包
defn = function(event) {
//这样最后传给监听函数的参数是经包装过Event对象
event = new Event(event, self.getWindow());
//这个条件用于扩展内置事件
if (condition.call(self, event) === false) event.stop();
};
}
//最终还是调用addListener
this.addListener(realType, defn);
}
//添加到列表
events[type].values.push(defn);
return this;
},
//移除事件监听
removeEvent: function(type, fn) {
//取临时对象,不提供默认值
var events = this.retrieve('events');
//如果临时对象不存在,说明监听不存在,直接返回
if (!events || !events[type]) return this;
//检查是否已添加本监听
var pos = events[type].keys.indexOf(fn);
//没有则返回
if (pos == -1) return this;
//从队列中移除
var key = events[type].keys.splice(pos, 1)[0];
var value = events[type].values.splice(pos, 1)[0];
//自定义事件处理
var custom = Element.Events.get(type);
//如果是自定义事件
if (custom) {
//自定义事件的移除处理
if (custom.onRemove) custom.onRemove.call(this, fn);
type = custom.base || type;
}
//如果是内置事件还需要调用removeListener来处理
return (Element.NativeEvents[type]) ? this.removeListener(type, value) : this;
},
//批量添加事件监听
addEvents: function(events) {
for (var event in events) this.addEvent(event, events[event]);
return this;
},
//批量移除事件监听
removeEvents: function(type) {
//取临时对象,不提供默认值
var events = this.retrieve('events');
//没有事件监听直接返回
if (!events) return this;
//如果不提供type参数,移除所有类型的事件
if (!type) {
for (var evType in events) this.removeEvents(evType);
events = null;
} else if (events[type]) {
//移除指定类型的事件
while (events[type].keys[0]) this.removeEvent(type, events[type].keys[0]);
events[type] = null;
}
return this;
},
//事件通知
fireEvent: function(type, args, delay) {
//取临时对象,不提供默认值
var events = this.retrieve('events');
//没有事件监听
if (!events || !events[type]) return this;
events[type].keys.each(function(fn) {
//注意事件监听的函数中this默认指向当前Element
fn.create({'bind': this, 'delay': delay, 'arguments': args})();
}, this);
return this;
},
//事件复制
cloneEvents: function(from, type) {
//事件源
from = $(from);
var fevents = from.retrieve('events');
if (!fevents) return this;
//不提供type参数则复制所有事件
if (!type) {
for (var evType in fevents) this.cloneEvents(from, evType);
} else if (fevents[type]) {
//复制指定类型的事件
fevents[type].keys.each(function(fn) {
this.addEvent(type, fn);
}, this);
}
return this;
}
});
//内置事件,分两种类型
Element.NativeEvents = {
click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons
mousewheel: 2, DOMMouseScroll: 2, //mouse wheel
mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement
keydown: 2, keypress: 2, keyup: 2, //keyboard
focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements
load: 1, unload: 1, beforeunload: 1, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window
error: 1, abort: 1, scroll: 1 //misc
};
//就地执行的匿名函数
(function() {
var $check = function(event) {
var related = event.relatedTarget;
if (related == undefined) return true;
if (related === false) return false;
return ($type(this) != 'document' && related != this && related.prefix != 'xul' && !this.hasChild(related));
};
//基于原事件扩展出的自定义事件
Element.Events = new Hash({
//鼠标进入事件
mouseenter: {
base: 'mouseover',
condition: $check
},
//鼠标离开事件
mouseleave: {
base: 'mouseout',
condition: $check
},
//鼠标滚轮事件
mousewheel: {
base: (Browser.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel'
}
});
})();