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

你可能感兴趣的:(framework)