zoukankan      html  css  js  c++  java
  • mass Framework event模块

    此模块此用于屏蔽DOM事件的浏览器差异的,并提供强大的事件代理机制(delegate,undelegate,live,die):

    
    //==========================================
    //  事件模块 by 司徒正美 2011.8.21
    //==========================================
    
    (function(global,DOC){
        var dom = global[DOC.URL.replace(/(#.+|\W)/g,'')];
        dom.define("event", "emitter,travel",function(){
            dom.log("加载dom.event模块成功")
            var types = "contextmenu,click,dblclick,mouseout,mouseover,mouseenter,mouseleave,mousemove,mousedown,mouseup,mousewheel," +
            "abort,error,load,unload,resize,scroll,change,input,select,reset,submit,"+"blur,focus,focusin,focusout,"+"keypress,keydown,keyup";
            dom.eventSupport = function( eventName,el ) {
                el = el || DOC.createElement("div");
                eventName = "on" + eventName;
                var ret = eventName in el;
                if (el.setAttribute && !ret ) {
                    el.setAttribute(eventName, "return;");
                    ret = typeof el[eventName] === "function";
                }
                el = null;
                return ret;
            };
            var events = dom.events, specials = events.special, rword = dom.rword;
            //用于在标准浏览器下模拟mouseenter与mouseleave
            //现在除了IE系列支持mouseenter/mouseleave/focusin/focusout外
            //opera11也支持这四个事件,同时它们也成为w3c DOM3 Event的规范
            //详见http://www.filehippo.com/pl/download_opera/changelog/9476/
            //http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html
            var brokenMouseEnter = !dom.eventSupport("mouseenter");
            "mouseenter_mouseover,mouseleave_mouseout".replace(rword,function(types){
                types = types.split("_");
                var obj = specials[ types[0] ]  = {
                    setup:function(target){
                        dom.bind(target, types[1],function(){
                            obj[uuid(target)+"_handle"] = arguments.callee;
                            e = events.fix(e);
                            var parent = e.relatedTarget;
                            try {
                                while ( parent && parent !== target ) {
                                    parent = parent.parentNode;
                                }
                                if ( parent !== target ) {
                                    e.type = types[0];
                                    events.handle.call(target,e);
                                }
                            } catch(e) { };
                        });
                    },
                    teardown :function(target){
                        events.teardown(target, types[1],obj[uuid(target)+"_handle"]);
                        delete obj[uuid(target)+"_handle"]
                    }
                };
                obj.liveSetup = obj.setup;
                obj.liveTeardown = obj.teardown;
                if(!brokenMouseEnter){
                    delete obj.setup;
                    delete obj.teardown;
                }
            });
    
            if(!dom.eventSupport("focusin")){
                "focusin_focus,focusout_blur".replace(rword,function(types){
                    types = types.split("_");
                    var attaches = 0;
                    function handler(e) {
                        events.fire(e.target, types[0]);
                    }
                    specials[  types[0] ]  = {
                        type: types[1],
                        setup:function(){
                            if ( attaches++ === 0 ) {
                                DOC.addEventListener(  types[1], handler, true );
                            }
                        },
                        teardown: function() {
                            if ( --attaches === 0 ) {
                                DOC.removeEventListener( types[1], handler, true );
                            }
                        }
                    }
                });
            }
            //http://www.w3help.org/zh-cn/causes/SD9013
            //https://prototype.lighthouseapp.com/projects/8886/tickets/697-eventfire-to-support-all-events-not-only-custom-ones
            //http://www.quirksmode.org/dom/events/scroll.html
            if(!dom.eventSupport("mousewheel")){
                specials.mousewheel = {
                    type    : "DOMMouseScroll"//FF
                }
            }
            //取得事件发送器的uniqueID
            function uuid(target){
                return dom.data(target,"uuid")
            }
            //submit事件的冒泡情况----IE6-9 :form ;FF: document; chrome: window;safari:window;opera:window
            if(!dom.eventSupport("submit") && !DOC.dispatchEvent ){
                var submitCode = dom.oneObject("13,108");
                var submitButton = dom.oneObject("submit,image");
                var submitInput = dom.oneObject("text,password,textarea");
                var submitRoom = specials.submit = {
                    liveSetup: function(target){
                        //将事件回调函数保存到一个在卸载时可以找到它的地方
                        submitRoom[uuid(target)+"_handle"] =  function(){
                            var e = events.fix(event), el = e.target, type = el.type;
                            if( el.form &&  ( submitButton[type] || submitCode[ e.which ] && submitInput[type]) ){
                                dom.log("模拟IE下的submit事件冒泡 ");
                                e.type = "submit";
                                events.handle.call(target, e);
                            }
                        }
                        "onclick,onkeypress".replace(rword,function(type){
                            target.attachEvent(type ,submitRoom[uuid(target)+"_handle"] );
                        })
                    },
                    liveTeardown: function(target){
                        "onclick,onkeypress".replace(rword,function(type){
                            target.detachEvent(type ,submitRoom[uuid(target)+"_handle"]||dom.noop );
                        });
                        delete submitRoom[uuid(target)+"_handle"];
                    }
                }
            }
            //reset事件的冒泡情况----FF与opera能冒泡到document,其他浏览器只能到form
            if(!dom.eventSupport("reset") ){
                var resetRoom = specials.reset = {
                    liveSetup:DOC.dispatchEvent ? 0 : function(target){
                        resetRoom[uuid(target)+"_handle"] =  function(){
                            var e = events.fix(event), el = e.target;
                            if(  el.form && (e.which === 27  ||  el.type == "reset") ){
                                dom.log("模拟reset事件冒泡 ");
                                e.type = "reset";
                                events.handle.call(target, e);
                            }
                        }
                        "onclick,onkeypress".replace(rword,function(type){
                            target.attachEvent(type , resetRoom[uuid(target)+"_handle"]);
                        });
                    },
                    liveTeardown:DOC.dispatchEvent ? 0 : function(target){
                        "onclick,onkeypress".replace(rword,function(type){
                            target.dettachEvent(type ,resetRoom[uuid(target)+"_handle"]);
                        })
                        delete resetRoom[uuid(target)+"_handle"];
                    }
                }
            }
            //change事件的冒泡情况----FF与opera能冒泡到document,其他浏览器完全不冒泡
            if(!dom.eventSupport("change") ){
                function getVal( node ) {
                    var type = node.type, val = node.value;
                    if ( type === "radio" || type === "checkbox" ) {
                        val = node.checked;
                    } else if ( type === "select-multiple" ) {
                        val = node.selectedIndex === -1 ? "":
                        dom.lang( node.options).map(function( node ) {
                            return node.selected;
                        }).join("-") ;
                    } else if ( type === "select-one" ) {
                        val = node.selectedIndex;
                    }
                    return val;
                }
                function changeHandle( e ) {
                    var  eType = e.type,node = e.srcElement,nType = node.type
                    //如果不是表单元素,又或者处于只读状态下,直接返回
                    if ( !node.form || node.readOnly ) {
                        return;
                    }
                    if ( eType === "keydown" ) {
                        var flag = false;
                        if ( (e.keyCode === 13 && nType !== "textarea"  ) ||
                            (e.keyCode === 32 && ( nType === "checkbox" || nType === "radio")) ||
                            nType === "select-multiple" ) {
                            flag = true;
                        }
                        if(!flag){
                            return;
                        }
                    }
                    //取得之前的数据
                    var oldData = dom.data( node, "_change_data" );
                    //获取现在的数据
                    var newData = getVal(node);
                    // focusout是不用重设数据的
                    if ( eType !== "focusout" || nType !== "radio" ) {
                        dom.data( node, "_change_data", newData );
                    }
                    if ( newData === undefined || newData === oldData ) {
                        return;
                    }
                    if ( oldData != null || newData ) {
                        e = events.fix(e);
                        e.type = "change";
                        events.handle.call(node, e);
                    }
                }
    
    
                var changeRoom = specials.change = {
    
                    liveSetup: function(node){
                        //此事件用于收集数据
                        node.attachEvent("onbeforeactivate", function( ) {
                            changeRoom[uuid(node)+event.type+"_handler"] = arguments.callee;
                            dom.data( node, "_change_data", getVal(node) );
                        });
                        ////当点击目标元素时,再点击页面的其他位置时,依次会发生如下事件beforeactivate  click | beforedeactivate focusout
                        "onfocusout,onbeforedeactivate,onclick,onkeydown".replace(rword,function(type){
                            node.attachEvent(type ,function(){
                                changeRoom[uuid(node)+event.type+"_handler"] = arguments.callee;
                                changeHandle.call(node, event);
                            });
                        });
                    },
                    liveTeardown:function(node){
                        var uid = uuid(node);
                        "focusout,beforedeactivate,click,keydown,beforeactivate".replace(rword,function(type){
                            node.detachEvent("on"+type,changeRoom[uid+type+"_handler"]||dom.noop );
                            delete changeRoom[uid+type+"_handler"]
                        });
                    }
                }
            }
    
            //当一个元素,或者其内部任何一个元素获得焦点的时候会触发这个事件。
            //这跟focus事件区别在于,他可以在父元素上检测子元素获取焦点的情况。
            //=================================
            dom.include({
                toggleClick:function(/*fn1,fn2,fn3*/){
                    var fns = [].slice.call(arguments), i = 0;
                    return this.click(function(e){
                        var fn  = fns[i++] || fns[i = 0, i++];
                        fn.call(this,e);
                    })
                },
                hover: function( fnOver, fnOut ) {
                    return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
                }
            });
            "bind,unbind,fire".replace(rword, function(method){
                dom.fn[method] = function(){
                    var args = arguments;
                    return this.each(function(target){
                        events[method].apply(target, args);
                    });
                }
    
            });
            //事件代理的原理就是把事件侦听器绑定在顶层元素上,通过判定下层冒泡或捕获上来的事件源元素的特定,执行相应的回调
            "delegate,undelegate".replace(rword,function(method){
                dom.fn[method] = function(expr,type,callback){
                    var special = events.special[ type ] || {};
                    var bag = {
                        live: expr,
                        type: type,
                        callback:callback
                    }
                    bag.uuid =  callback.uuid = dom.uuid++;
                    //选取可用的事件类型,如mouseenter在标准浏览器下就不能用,需要用mouseover冒充
                    type = special.type || type
                    return this.each(function(node){
                        events[method === "delegate" ? "bind" : "unbind"].apply(node, [type, bag, true]);
                    });
                }
            });
            "live,die".replace(rword,function(method){
                dom.fn[method] = function(type,callback){
                    var expr = this.selector;
                    var doc = this.doc || DOC;
                    if(!expr){
                        expr = dom.noop;
                    }
                    return dom(doc)[method === "live" ? "delegate" : "undelegate"](expr, type, callback);
                }
            });
            types.replace(rword,function(type){
                dom.fn[type] = function(callback, phase, trust){
                    return this.bind(type, callback, phase, trust);
                }
            });
        });
    })(this,this.document);
    

    相关链接:dom Framework emitter模块

  • 相关阅读:
    查看文件夹内各文件数目
    Resnet论文翻译
    查看keras自动给文件夹标号
    文件夹内自动图片遍历
    将wiki人脸数据集的性别信息提取出来制作标签
    将wiki人脸数据集中的图片按男女分类
    IPFS私有网络集群搭建
    带参数的函数增加装饰器
    【IPFS + 区块链 系列】 入门篇 — IPFS环境配置
    程序员那些事儿:技术骨干的烦恼
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/2147780.html
Copyright © 2011-2022 走看看