mass Framework emitter模块-程序员宅基地

此模块用于提供自定义事件,并把实现此接口的对象变成一个事件发送器。


//==================================================
// 事件发送器模块
//==================================================
(function(global,DOC){
    var dom = global[DOC.URL.replace(/(#.+|\W)/g,'')];
    dom.define("emitter","data", function(){
        var fireType = "", blank = ""
        var ensure = function(array,neo){
            var obj = {}
            for(var i=0,el;el = array[i++];){
                obj[ el.uuid ] =1
            }
            if(!obj[neo.uuid]){
                array.push(neo)
            };
        }
        var events = dom.events = {
            special:{},//用于处理个别的DOM事件
            bind : function(type, callback, phase){
                //它将在原生事件发送器或任何能成为事件发送器的普通JS对象添加一个名叫uniqueID的属性,用于关联一个缓存体,
                //把需要的数据储存到里面,而现在我们就把一个叫@events的对象储放都它里面,
                //而这个@event的表将用来放置各种事件类型与对应的回调函数
                var target = this, table = dom.data( target,"@events") || dom.data( target,"@events",{});
                if(!table || !callback) return ;
                var bag = callback.callback ? callback :{
                    callback:callback,
                    uuid: dom.uuid++,
                    type:type
                }
                //确保UUID,bag与callback的UUID一致
                bag.callback.uuid = bag.uuid;
                //原生的DOM事件是不允许绑定同一个回调函数,详见下面的测试
                //  function callback(){  alert(1)  }
                //  document.addEventListener("click",callback,false)
                //  document.addEventListener("click",callback,false)
                type = bag.type;
                var queue = table[ type ] = table[ type ] ||  [];
                ensure(queue,bag);
                if(dom["@emitter"] in target){//如果是原生的事件发送体
                    var special = events.special[ bag.type ] , setup = events.setup, tag = "@"+type
                    if(special){
                        type = special.type || type
                        tag = (bag.live ? "@live_" :"@special_" )+type;
                        setup = bag.live ? special.liveSetup : special.setup
                    }
                    bag.tag = tag;
                    if(!table[tag]){
                        dom.log("setup "+type+" event...")
                        setup(target, type, events.handle, !!phase);
                        table[tag] = 1
                    }
                }
            },
  
            unbind:function(type ,bag, phase){
                var target = this, table = dom.data( target,"@events") ;
                if(!table) return;
                if(typeof type === "string"){//如果指定了要移除何种事件类型
                    type = bag && bag.type || type;
                    var queue = table[ type ];
                    if(queue){
                        var callback = bag.callback || bag;
                        queue =  callback ? table[type].filter(function(bag) {
                            return  bag.callback != callback;
                        }) : [];
                        if(dom["@emitter"] in target){//如果是原生的事件发送体
                            var special = events.special[ type ] ,  teardown = events.teardown, tag = "@"+type
                            if(special){
                                type = special.type || type
                                tag = (bag.live ? "@live_" :"@special_" )+type;
                                teardown = bag.live ? special.liveTeardown : special.teardown
                            }   
                            var length =  queue.filter(function(bag){
                                return bag.tag == tag
                            }).length;
                            if(!length){
                                teardown(target, type, events.handle, !!phase) ;
                                dom.log("teardown "+type+" event...")
                                delete table[tag]
                            }
                        }
                    }
                }else{
                    for (type in table ) {
                        if(type.charAt(0) !== "@")
                            events.unbind( target, type );
                    }
                }
            },
            fire:function(type){
                var target = this, table = dom.data( target,"@events") ,args = dom.slice(arguments,1), event
                if(!table) return;
                event = type instanceof jEvent ? type : new jEvent(type);
                event.target = target;
                event.fireArgs = args;
                if( dom["@emitter"] in target){
                    var cur = target,  ontype = "on" + type;
                    do{//模拟事件冒泡与执行内联事件
                        events.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;
                        try {
                            if (ontype && target[ type ]) {
                                // 不用再触发内事件
                                old = target[ ontype ];
                                if (old) {
                                    target[ ontype ] = null;
                                }
                                fireType = type;
                                target[ type ]();
                            }
                        } catch (e) {
                            dom.log("dom.events.fire("+type+") throw errer " + e);
                        }
                        if (old) {
                            target[ ontype ] = old;
                        }
                        fireType = blank;
                    }
  
                }else{//普通对象的自定义事件
                    events.handle.call(target, event);
                }
            },
            filter:function(target, parent, expr){
                if(dom.contains(parent,target) ){
                    if(typeof expr === "function"  ){
                        return expr.call(target)
                    }else{
                        return dom.matchesSelector(target, expr) ;//需要travel模块
                    }
                }
            },
            handle: function( event ) {
                if(fireType === event.type)
                    return undefined;
                var queue = dom.data(this,"@events")[event.type];
                if (  queue ) {
                    if(!event.uuid){
                        event = events.fix(event);
                    }
                    event.currentTarget = this;
                    var emitter = event.target, result,
                    //取得参数(只有自定义才有多个参数)
                    args = "fireArgs" in event ? [event].concat(event.fireArgs) : arguments;
                    //复制数组以防影响下一次的操作
                    queue = queue.concat();
                    //开始进行拆包操作
                    for ( var i = 0, bag; bag = queue[i++]; ) {
                        //如果是事件代理,确保元素处于enabled状态,并且满足过滤条件
                        if(bag.live && emitter.disabled && !events.filter(emitter, this, bag.live) ){
                            continue;
                        }
                        //取得回调函数
                        result = bag.callback.apply( emitter, 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(event.uuid){
                    return event;
                }
                var originalEvent = event
                event = new jEvent(originalEvent);
                for(var prop in originalEvent){
                    if(typeof originalEvent[prop] !== "function"){
                        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;
                }
                //如果事件源对象为文本节点,则置入其父元素
                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 html = dom.HTML, 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:DOC.dispatchEvent ? function(target, type, fn,phase){
                target.removeEventListener( type, fn,phase );
            } : function(target, type, fn)  {
                target.detachEvent( "on" + type, fn );
            }
        }
        function jEvent( event ) {
            this.originalEvent = event.substr ? {} : event
            this.type = event.type || event
            this.timeStamp = Date.now();
            this.uuid = dom.uuid++;
        };
        // 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(){
                events[name].apply(this, arguments);
                return this;
            }
        });
        dom.emitter.uniqueID = ++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, Array.prototype.concat.apply([name],arguments));
                    };
                }
            },this);
        }
    });
})(this,this.document);
//2011.8.14
//更改隐藏namespace,让自定义对象的回调函数也有事件对象
//2011.8.17
//事件发送器增加一个uniqueID属性
//2011.8.21
//重构bind与unbind方法

示例:


       dom.require("ready,class,emitter",function(){
        var A = dom.factory({
          include:dom.emitter,
          init:function(){
            this.defineEvents("click,mouseover")
          }
        });

        var a = new A;
        a.bind("click",function(){
          alert([].slice.call(arguments))//[object Event],1,2,3
        })
        a.fire("click",1,2,3);
        a.onMouseover(function(){
          alert("司徒正美")
        });
        a.fire("mouseover")
        dom.log(a)
      })

依次弹出两个窗口,第一个为"1,2,3",第二个为"司徒正美".在firebug下查看a实例的构造如下:

o_dom_emitter_1.jpg

第二个例子,只依赖emitter模块.


      dom.require("emitter",function(){
        var a  = {};
        dom.mix(a,dom.emitter);
        a.bind("data",function(){
          alert("11111111")
        });
        a.bind("data",function(e){
          alert([].slice.call(arguments));//[object Event],3,5
          alert(e.type) //data
        });
        a.fire("data",3,5)
 
      });

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_33859665/article/details/85492239

智能推荐

apksigner完成apk的签名_apksigner 签名-程序员宅基地

文章浏览阅读2.3k次。有时候用第三方加固平台加固以后会让我们重新签名。还有就是上应用市场的时候,如果以前该应用已经在市场上上传过了,由于后面业务原因换了开发者账号再去上传就会提示我们去认领一个没有签名的包(unsign.apk),然后去签名上传进行MD5签名验证,如下图看到上面的提示不要慌,不就是加个签名么,apksigner就是SDK自带的签名工具,处于F:\android-sdk\build-tools\xxx目录下将上面的路径配置到系统环境变量path中,打开cmd,切换到unsign.apk目录下,建议.._apksigner 签名

java内省机制及PropertyUtils使用方法_propertyutils.snaketoline(field.getname());-程序员宅基地

文章浏览阅读1.3k次。背景 一般情况下,在Java中你可以通过get方法轻松获取beans中的属性值。但是,当你事先不知道beans的类型或者将要访问或修改的属性名时,该怎么办?Java语言中提供了一些像java.beans.Introspector这样类,实现了在运行时检测Java类并确定属性get和set方法的名称,结合Java中的反射机制就可以调用这些方法了。然而,这些APIs使用起来比较_propertyutils.snaketoline(field.getname());

LeetCode 516. Longest Palindromic Subsequence--最长回文子序列长度_leetcode longestpalindromesubseq连续字符不想等,长度为偶的回文子序列-程序员宅基地

文章浏览阅读536次。Given a string s, find the longest palindromic subsequence's length in s. You may assume that the maximum length of s is 1000.Example 1:Input:"bbbab"Output:4One possible longest palind_leetcode longestpalindromesubseq连续字符不想等,长度为偶的回文子序列长度

Android自定义View之自定义加载进度条(二)-程序员宅基地

文章浏览阅读189次。本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点自定义加载进度条Android自定义View之手把手带你自定义一个进度条上次我们已经把实线和虚线都绘制好了,这次我们就主要来解决更新的问题:怎么随着时间的推移逐渐地绘制进度条怎么在绘制的过程中加速进度条的绘制首先我们来解决第一个问题,也就是随着时间更新我们的..._setvalueinterpolator

c#判断字符串是否json-程序员宅基地

文章浏览阅读5.7k次。来源:https://www.cnblogs.com/cyq1162/p/3841766.html下载地址:  https://github.com/cyq1162/cyqdata/blob/master/Tool/JsonSplit.cs  https://github.com/cyq1162/cyqdata  using System;using System.C..._c#判断是json还是xml

python读取eml文件并用正则匹配邮箱_python 如何查看eml文件-程序员宅基地

文章浏览阅读992次。python读取eml文件并用正则匹配邮箱_python 如何查看eml文件

随便推点

Jquery插件之DataTables初探_jquery datatables 英文-程序员宅基地

文章浏览阅读2.5k次。今天闲来无事,就研究了一下Jquery的DataTables插件。感觉效果不错,支持排序和内容过滤(查询),在这里向大家推荐一下^_^不得不说之前犯了一个错误,这个插件应该叫做DataTable,而我把它当成了tablesort,实在不好意思。。。。。可以直接到官网上去下载下来,单击http://www.datatables.net/到官网上看看,什么API、demo之类的_jquery datatables 英文

算法:逆序对-程序员宅基地

文章浏览阅读8.5k次,点赞8次,收藏11次。逆序对什么是逆序对呢?百度百科这样解释:设 A 为一个有 n 个数字的有序集 (n>1),其中所有数字各不相同。如果存在正整数 i, j 使得 1 ≤ i < j ≤ n 而且 A[i] > A[j],则 <A[i], A[j]> 这个有序对称为 A 的一个逆序对,也称作逆序数。定义:对于一个包含N个非负整数的数组A[1…n],如果有i < j,且A[ i ]>A[ j ],则称(A[ i] ,A[ j] )为数组A中的一个逆序对。例如,数组(3_逆序对

SLAM导航机器人零基础实战系列:(四)差分底盘设计——3.底盘通信协议_slam 实战-程序员宅基地

文章浏览阅读1.2k次。SLAM+语音机器人DIY系列:(四)差分底盘设计——3.底盘通信协议摘要 运动底盘是移动机器人的重要组成部分,不像激光雷达、IMU、麦克风、音响、摄像头这些通用部件可以直接买到,很难买到通用的底盘。一方面是因为底盘的尺寸结构和参数是要与具体机器人匹配的;另一方面是因为底盘包含软硬件整套解决方案,是很多机..._slam 实战

LOJ #6010. 「网络流 24 题」数字梯形-程序员宅基地

文章浏览阅读89次。#6010. 「网络流 24 题」数字梯形题目描述给定一个由n nn行数字组成的数字梯形如下图所示。梯形的第一行有m mm个数字。从梯形的顶部的m mm个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶至底的路径。分别遵守以下规则:从梯形的顶至底的m mm条路径互不相交;从梯形的顶至底的m mm..._7-60 数字梯形 (110 分) 给定一个由n行数字组成的数字梯形如下图所示。梯形的第一

Ubuntu20.04 + RTX 3090(兼容RTX 2080 Ti) + Pytorch1.7配置方法_2080ti ubuntr20.04-程序员宅基地

文章浏览阅读2.2k次。背景介绍:由于在Ubuntu16.04系统上安装RTX 3090显卡驱动有点吃力(各种Error和不兼容),使用最新Ubuntu20.04系统搭配最新的RTX 3090显卡配置最新的Pytorch【(*^▽^*)】前期准备: 1、Ubuntu20.04下载:Ubuntu20.4_amd64_desktop.iso 2、UNtebootin光盘刻录软件下载:unetbootin,选择Windows下载 3、NVID..._2080ti ubuntr20.04

Struts + Spring +ibatis 整合开发步骤_struts+spring+ibatis-程序员宅基地

文章浏览阅读329次。一.添加Spring 、Struts框架对web.xml文件的修改1. 添加Spring框架2. 在web.xml中引入Spring配置文件(注意:applicationContext.xml文件的路径)context-param> param-name>contextConfigLocationparam-name> param-v_struts+spring+ibatis