zoukankan      html  css  js  c++  java
  • 读Ext之九(事件管理)

    Ext的事件管理非常强大。主要定义在Ext.EventManager对象(单例模式)中。该对象有以下方法

    addListener 
    removeListener
    removeAll
    getListeners
    purgeElement
    _unload
    onDocumentReady
    on
    un
    stoppedMouseDownEvent
     

    on / un 是 addListener / removeListener的快捷方式 。
    stoppedMouseDownEvent 是  Ext.util.Event 类的实例对象,这个类定义在Observable.js中。
    stoppedMouseDownEvent 在Ext.EventObject 类中用到。

    使用Ext.EventManager.on添加事件很简单

    <p id="p1" style="background:gold;">
    	HELLO
    </p>
    <script type="text/javascript">
    	var p1 = document.getElementById('p1');
    	function f1(){alert(this)}
    	Ext.EventManager.on(p1,'click',f1);	
    </script>
    

    这样就为段落P添加了一个单击事件。默认情况下执行上下文就是HtmlElement自身。当然可以使用第四个参数scope指定上下文。

    <script type="text/javascript">
    	var p1 = document.getElementById('p1');
    	function f1(){alert(this)}
    	Ext.EventManager.on(p1,'click',f1,window);	
    </script>
    

    第五个参数是个对象,属性介绍分别如下:


    scope : 可指定执行上下文
    delegate :事件代理
    stopEvent :阻止冒泡和默认行为
    preventDefault :阻止默认行为
    stopPropagation :停止事件冒泡
    normalized : 仅传原生事件对象
    delay :延迟执行
    single : 仅执行一次
    buffer :延迟执行,多次时最后一次覆盖前一次
    target : 指定在父元素上执行

    下图是Ext.EventManager.addListener的详细接口说明

    下面看看源码是如何实现的

    addListener : function(element, eventName, fn, scope, options){
        if(Ext.isObject(eventName)){
            var o = eventName, e, val;
            for(e in o){
                val = o[e];
                if(!propRe.test(e)){
                    if(Ext.isFunction(val)){
                        // shared options
                        listen(element, e, o, val, o.scope);
                    }else{
                        // individual options
                        listen(element, e, val);
                    }
                }
            }
        } else {
            listen(element, eventName, options, fn, scope);
        }
    },
    

    可以看到其中调用私有 listen 函数,但存在三种分支情况。暂且考虑第三者情况listen(element, eventName, options, fn, scope);

    listen 函数定义如下

    function listen(element, ename, opt, fn, scope){
        var o = !Ext.isObject(opt) ? {} : opt,
            el = Ext.getDom(element), task;
    
        fn = fn || o.fn;
        scope = scope || o.scope;
    
        if(!el){
            throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
        }
        function h(e){
            // prevent errors while unload occurring
            if(!Ext){// !window[xname]){  ==> can't we do this?
                return;
            }
            e = Ext.EventObject.setEvent(e);
            var t;
            if (o.delegate) {
                if(!(t = e.getTarget(o.delegate, el))){
                    return;
                }
            } else {
                t = e.target;
            }
            if (o.stopEvent) {
                e.stopEvent();
            }
            if (o.preventDefault) {
               e.preventDefault();
            }
            if (o.stopPropagation) {
                e.stopPropagation();
            }
            if (o.normalized) {
                e = e.browserEvent;
            }
    
            fn.call(scope || el, e, t, o);
        };
        if(o.target){
            h = createTargeted(h, o);
        }
        if(o.delay){
            h = createDelayed(h, o, fn);
        }
        if(o.single){
            h = createSingle(h, el, ename, fn, scope);
        }
        if(o.buffer){
            task = new Ext.util.DelayedTask(h);
            h = createBuffered(h, o, task);
        }
    
        addListener(el, ename, fn, task, h, scope);
        return h;
    };
    

    比较长,执行流程如下

    1,options参数未传,使用空对象{}。(接口的第5个参数)
    2,通过Ext.getDom获取HTMLElement元素(接口的第1个参数)。
    3, 响应函数先取fn(接口的第3个参数),没传则取opt.fn上。
    4, 执行上下文先取scope(接口的第4个参数),没有则取opt.scope。
    5,el不存在,抛异常
    6, 内部函数h包装了客户端传入的函数fn,将原生事件对象偷偷转换成Ext包装后的事件对象Ext.EventObject。依次根据所传opt参数进行对应的操作。最后一句是核心

    fn.call(scope || el, e, t, o);
    

    响应函数fn真正的执行。

    7, 根据opt参数进行对应的操作:o.target,o.delay,o.single和o.buffer。
    8, 调用私有的addListener函数。

    私有的addListener定义如下:

    /// There is some jquery work around stuff here that isn't needed in Ext Core.
    function addListener(el, ename, fn, task, wrap, scope){
        el = Ext.getDom(el);
        var id = getId(el),
            es = Ext.elCache[id].events,
            wfn;
        wfn = E.on(el, ename, wrap);
        es[ename] = es[ename] || [];
    
        /* 0 = Original Function,
           1 = Event Manager Wrapped Function,
           2 = Scope,
           3 = Adapter Wrapped Function,
           4 = Buffered Task
        */
        es[ename].push([fn, wrap, scope, wfn, task]);
    
    
        // this is a workaround for jQuery and should somehow be removed from Ext Core in the future
        // without breaking ExtJS.
        if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
            var args = ["DOMMouseScroll", wrap, false];
            el.addEventListener.apply(el, args);
            Ext.EventManager.addListener(WINDOW, 'unload', function(){
                el.removeEventListener.apply(el, args);
            });
        }
        if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
            Ext.EventManager.stoppedMouseDownEvent.addListener(wrap);
        }
    };
    

    该函数中最重要一句

    wfn = E.on(el, ename, wrap);
    

    E.on 是 Ext.lib.Event.on,即 第四篇 提到的事件的低级封装。

    此外将返回对象wfn存在数组中。整个Ext添加事件的调用流程就是如此。

    EventManager.js

  • 相关阅读:
    perl Exporter一些神奇写法
    perl eval函数
    hibernate 映射文件配置默认值方法
    JavaWeb 服务启动时,在后台启动加载一个线程。
    根据input 标签取value属性的值
    perl 继承小例子
    net.sf.json.JSONException: Found starting '{' but missing '}' at the end. at character 0 of null
    Uncaught TypeError: Cannot read property 'plugin' of undefined
    mysql 密码过期问题 password_expired

  • 原文地址:https://www.cnblogs.com/snandy/p/2475640.html
Copyright © 2011-2022 走看看