mass Framework emitter模块 v2
此模块用于提供自定义事件,并把实现此接口的对象变成一个事件发送器。
//==================================================
// 事件发送器模块
//==================================================
(function(global,DOC){
var dom = global[DOC.URL.replace(/(#.+|\W)/g,'')];
dom.define("emitter","data", function(){
var fireType = "", blank = ""
var rhoverHack = /\bhover(\.\S+)?/,
rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, reprop = /[a-z]/;
var system = dom.event = {
special:{},//用于处理个别的DOM事件
bind : function( types, handler, selector){
//它将在原生事件发送器或任何能成为事件发送器的普通JS对象添加一个名叫uniqueNumber的属性,用于关联一个缓存体,
//把需要的数据储存到里面,而现在我们就把一个叫@events的对象储放都它里面,
//而这个@event的表将用来放置各种事件类型与对应的回调函数
var target = this, events = dom._data( target) , nativeEmitter = dom["@emitter"] in target,
all, tns ,type, namespace, special, handlerObj, handlers, fn;
if(target.nodeType === 3 || target.nodeType === 8 || !types || typeof handler !=="function" || !events) return ;
all = {
handler:handler,
uuid: dom.uuid++
}
//确保UUID,bag与callback的UUID一致
all.handler.uuid = all.uuid;
if(nativeEmitter ){
//处理DOM事件
fn = events.handle || (events.handle = function( e ) {
return ((e || event).type !== fireType) ? system.handle.apply( fn.target, arguments ) :void 0;
});
fn.target = target;
types = types.replace( rhoverHack, "mouseover$1 mouseout$1" )
}
events = events.events || (events.events = {});
//对多个事件进行绑定
types.replace(dom.rword,function(type){
tns = rtypenamespace.exec( type ) || [];
type = tns[1];//取得事件类型
namespace = (tns[2] || "").split( "." ).sort();//取得命名空间
//事件冒充只用于原生事件发送器
special = nativeEmitter && system.special[ type ] || {};
type = (selector? special.delegateType : special.bindType ) || type;
special = nativeEmitter && system.special[ type ] || {};
handlerObj = dom.mix({
type: type,
origType: tns[1],
selector: selector,
namespace: namespace.join(".")
}, all);
//创建事件队列
handlers = events[ type ] = events[ type ] || [];
//只有原生事件发送器才能进行DOM level2 多投事件绑定
if(nativeEmitter && !handlers.length ){
if (!special.setup || special.setup( target, selector, fn ) === false ) {
// 为此元素这种事件类型绑定一个全局的回调,用户的回调则在此回调中执行
dom.bind(target,type,fn,!!selector)
}
}
handlers.push( handlerObj );
});
},
unbind: function( types, handler, selector ) {
var target = this, events = dom._data( target,"events")
if(!events) return;
var t, tns, type, namespace, origCount,nativeEmitter = dom["@emitter"] in target,
j, special, handlers, handlerObj;
types = nativeEmitter ? (types || "").replace( rhoverHack, "mouseover$1 mouseout$1" ) : types;
types = (types || "").split(" ");
for ( t = 0; t < types.length; t++ ) {
tns = rtypenamespace.exec( types[t] ) || [];
type = tns[1];
namespace = tns[2];
// 如果types只包含命名空间,则去掉所有拥有此命名空间的事件类型的回调
if ( !type ) {
namespace = namespace? "." + namespace : "";
for ( j in events ) {
system.unbind.call( target, j + namespace, handler, selector );
}
return;
}
//如果使用事件冒充则找到其正确事件类型
special = system.special[ type ] || {};
type = (selector? special.delegateType : special.bindType ) || type;
handlers = events[ type ] || [];
origCount = handlers.length;
namespace = namespace? namespace.split( "." ).sort().join(".") : null;
//只有指定了命名空间,回调或选择器才能进入此分支
if ( handler || namespace || selector ) {
for ( j = 0; j < handlers.length; j++ ) {
handlerObj = handlers[ j ];
if ( !handler || handler.uuid === handlerObj.uuid ) {
if ( !namespace || namespace === handlerObj.namespace ) {
if ( !selector || selector === handlerObj.selector || selector === "**" && handlerObj.selector ) {
handlers.splice( j--, 1 );
}
}
}
}
} else {
//移除此类事件的所有回调
handlers.length = 0;
}
if (nativeEmitter && (handlers.length === 0 && origCount !== handlers.length) ) {
if ( !special.teardown || special.teardown( target, selector, handler ) === false ) {
dom.unbind( target, type, dom._data(target,"handle") );
}
delete events[ type ];
}
}
if(dom.isEmptyObject(events)){
var handle = dom.removeData( target,"handle") ;
handle.elem = null;
dom.removeData( target,"events") ;
}
},
fire:function(event){
var target = this, namespace = [], type = event.type || event
if ( type.indexOf( "." ) !== -1 ) {
namespace = type.split(".");
type = namespace.shift();
namespace.sort();
}
var events = dom._data( target,"events") ,args = dom.slice(arguments,1)
if(!events) return;
event = (typeof event == "object" && "namespace" in event)? type : new jEvent(type);
event.target = target;
event.fireArgs = args;
event.namespace = namespace.join( "." );
if( dom["@emitter"] in target){
var special = system.special[ type ] || {};
if ( special.fire && special.fire.call( target, event ) === false ) {
return;
}
var cur = target, ontype = "on" + type;
do{//模拟事件冒泡与执行内联事件
system.handle.call(cur, event);
if (cur[ ontype ] && cur[ ontype ].call(cur) === false) {
event.preventDefault();
}
cur = cur.parentNode ||
cur.ownerDocument ||
cur === target.ownerDocument && global;
} while (cur && !event.isPropagationStopped);
if (!event.isDefaultPrevented) {//模拟默认行为 click() submit() reset() focus() blur()
var old;
if (ontype && target[ type ] && ((type !== "focus" && type !== "blur") || target.offsetWidth !== 0) && !target.document) {
old = target[ ontype ];
if (old) { // 不用再触发内联事件
target[ ontype ] = null;
}
fireType = type;
target[ type ]();
}
fireType = blank;
if (old) {
target[ ontype ] = old;
}
}
}else{//普通对象的自定义事件
system.handle.call(target, event);
}
},
filter:function(cur, parent, expr){
for ( ; cur != parent; cur = cur.parentNode || parent ) {
if(dom.matchesSelector(cur, expr))
return true
}
return false;
},
handle: function( e ) {
var event = system.fix( e || event ),
handlers = dom._data(this,"events");
if ( handlers ) {
handlers = handlers[event.type]||[]
arguments[0] = event;
event.currentTarget = this;
var src = event.target, result,
//取得参数(只有自定义才有多个参数)
args = "fireArgs" in event ? [event].concat(event.fireArgs) : arguments;
//复制数组以防影响下一次的操作
handlers = handlers.concat();
//开始进行拆包操作
for ( var i = 0, obj; obj = handlers[i++]; ) {
//如果是事件代理,确保元素处于enabled状态,并且满足过滤条件
if ( !src.disabled && !(event.button && event.type === "click")
&& (!obj.selector || system.filter(src, this, obj.selector))
&& (!event.namespace || event.namespace === obj.namespace ) ) {
//取得回调函数
result = obj.handler.apply( src, args );
if ( result !== undefined ) {
event.result = result;
if ( result === false ) {
event.preventDefault();
event.stopPropagation();
}
}
if ( event.isImmediatePropagationStopped ) {
break;
}
}
}
}
return event.result;
},
fix :function(event){
if(!("namespace" in event)){
var originalEvent = event
event = new jEvent(originalEvent);
for(var prop in originalEvent){
//去掉所有方法与常量
if(typeof originalEvent[prop] !== "function" && reprop.test(prop)){
event[prop] = originalEvent[prop]
}
}
event.wheelDelta = 0;
//mousewheel
if ("wheelDelta" in originalEvent){
var detail = originalEvent.wheelDelta;
//opera 9x系列的滚动方向与IE保持一致,10后修正
if(global.opera && global.opera.version() < 10)
detail = -detail;
event.wheelDelta = Math.round(detail); //修正safari的浮点 bug
}else {
//DOMMouseScroll
event.wheelDelta = -originalEvent.detail*40;
}
//如果不存在target属性,为它添加一个
if ( !event.target ) {
// 判定鼠标事件按下的是哪个键,1 === left; 2 === middle; 3 === right
event.which = event.button === 2 ? 3 : event.button === 4 ? 2 : 1;
event.target = event.srcElement || DOC;
}
//如果事件源对象为文本节点,则置入其父元素
if ( event.target.nodeType === 3 ) {
event.target = event.target.parentNode;
}
//如果不存在relatedTarget属性,为它添加一个
if ( !event.relatedTarget && event.fromElement ) {
event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
}
//如果不存在pageX/Y则结合clientX/Y做一双出来
if ( event.pageX == null && event.clientX != null ) {
var doc = event.target.ownerDocument || DOC,
html = doc.documentElement, body = doc.body;
event.pageX = event.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0) - (html && html.clientLeft || body && body.clientLeft || 0);
event.pageY = event.clientY + (html && html.scrollTop || body && body.scrollTop || 0) - (html && html.clientTop || body && body.clientTop || 0);
}
// 为键盘事件添加which事件
if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {
event.which = event.charCode || event.keyCode;
}
// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
if ( !event.metaKey && event.ctrlKey ) {
event.metaKey = event.ctrlKey;
}
}
return event;
},
setup: dom.bind,
teardown:dom.unbind
}
var jEvent = dom.Event = function ( event ) {
this.originalEvent = event.substr ? {} : event;
this.type = event.type || event;
this.namespace = "";//用于判定是否为伪事件对象
};
// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
jEvent.prototype = {
constructor:jEvent,
//http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/events.html#Conformance
toString:function(){
return "[object Event]"
},
preventDefault: function() {
this.isDefaultPrevented = true;
var e = this.originalEvent;
// 如果存在preventDefault 那么就调用它
if ( e.preventDefault ) {
e.preventDefault();
}
// 如果存在returnValue 那么就将它设为false
e.returnValue = false;
return this;
},
stopPropagation: function() {
this.isPropagationStopped = true;
var e = this.originalEvent;
// 如果存在preventDefault 那么就调用它
if ( e.stopPropagation ) {
e.stopPropagation();
}
// 如果存在returnValue 那么就将它设为true
e.cancelBubble = true;
return this;
},
stopImmediatePropagation: function() {
this.isImmediatePropagationStopped = true;
this.stopPropagation();
return this;
}
};
//事件发射体emitter的接口
//实现了这些接口的对象将具有注册事件和触发事件的功能
dom.emitter = {};
"bind,unbind,fire".replace(dom.rword,function(name){
dom.emitter[name] = function(){
system[name].apply(this, arguments);
return this;
}
});
dom.emitter.uniqueNumber = ++dom.uuid;
dom.emitter.defineEvents = function(names){
var events = [];
if(typeof names == "string"){
events = names.match(dom.rword);
}else if(dom.isArray(names)){
events = names;
}
events.forEach(function(name){
var method = 'on'+name.replace(/(^|_|:)([a-z])/g,function($, $1, $2) {
return $2.toUpperCase();
});
if (!(method in this)) {
this[method] = function() {
return this.bind.apply(this, [].concat.apply([name],arguments));
};
}
},this);
}
});
})(this,this.document);
//2011.8.14 更改隐藏namespace,让自定义对象的回调函数也有事件对象
//2011.9.17 事件发送器增加一个uniqueID属性
//2011.9.21 重构bind与unbind方法 支持命名空间与多事件处理
//2011.9.27 uniqueID改为uniqueNumber 使用dom._data存取数据
//2011.9.29 简化bind与unbind
机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年
浙公网安备 33010602011771号