zoukankan      html  css  js  c++  java
  • 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
    
  • 相关阅读:
    codeforces 336D Vasily the Bear and Beautiful Strings(组合数学)
    13年山东省赛 The number of steps(概率dp水题)
    13年山东省赛 Mountain Subsequences(dp)
    13年山东省赛 Boring Counting(离线树状数组or主席树+二分or划分树+二分)
    codeforces 337C Quiz(贪心)
    codeforces 336C Vasily the Bear and Sequence(贪心)
    codeforces 335A Banana(贪心)
    codeforces 339C Xenia and Bit Operations(线段树水题)
    codeforces 339C Xenia and Weights(dp或暴搜)
    codeforces 340E Iahub and Permutations(错排or容斥)
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/2189933.html
Copyright © 2011-2022 走看看