YUI3 core阅读笔记

node-debug.js :

Node 为 HTMLElement包装(处理了缓存),关键 addMethod ,importMethod 将 Y.DOM 中的静态方法(YUI2模型)迁移到 Node实例中去.

Y.DOM.method(node,args); ==> node.method(args);

NodeList 为 多个 htmlelements的包装,关键也为 NodeList.addMethod 以及NodeList.importMethod,同Ext .compositeElement 类似
将Node的方法也加到NodeList中去,并调用时自动循环对nodelist中的所有元素调用对应方法。


event-custom-debug.js & event-simulate-debug.js

自定义事件处理系统和原生dom处理事件系统完全接口一致(不同于Extjs,node和组件的事件处理完全分离,yui3 Node和组件其实都是 augment 自 EventTarget):除了dom模拟触发需要 node.simulate 而自定义事件需要obj.fire。

YUI当前实例 Y 本身也 augment 自EventTarget,一些全局自定义事件比如windowresize,domready即由 Y触发,可以在Y上处理。

注意 node.simulate并没有采用 jquery自己遍历树结构,挨个执行处理函数的方式,而是利用了浏览器自身的event simulation framework,对于w3c-dom-event2兼容浏览器使用document.createEvent而对于ie则使用document.createEventObject


而dom事件通过 DOMEventFacade 来进行包装,保证各个浏览器的一致性。当emitFacade为true时复杂情况下的自定义事件触发使用 EventFacade 来包装,具有和DOMEventFacade基本一致的属性,EventFacade.detail为fire参数。

 

事件处理器统一用Subscriber包装,可以方便实现AOP,contextFn动态上下文环境的调用。


并且自定义事件也实现了bubble以及defaultFn功能
(publish必须设置emitFacade为true,调用fireComplex ) ,可方便的实现以前组件必须显式检查beforeShow以及调用者必须监听 beforeShow 等事件来实现AOP拦截,现在只需组件编写者申明事件的defaultFn以及调用者监听 on("show")决定是否preventDefault即可,bubble定义在 EventTarget 中,EventTarget可以通过addTarget添加事件往上传播的通知对象,使得自定义事件也可以通过delegate来简化事件处理。

 

EventTarget 还另外支持了 jquery 类似的分类事件功能,对同一个事件的一些监听器可以分做一类,类名放在事件名前面用|分隔,以及结合 Base 支持的前缀机制,可以解决不同类的同名事件监听问题,使用例子


event-debug.js

不同于dom-event2中添加多个事件处理器由浏览器调度,yui3以及ext每个事件每个元素底层只绑定一个dom2事件处理器,由这个dom2事件处理器再调用绑定在这个事件的所有事件处理函数。

Y.Env.evt.dom_wrappers 为对所有事件的统一处理封装,将每个dom事件映射为自定义事件,每个自定义事件有一个事件处理器绑定到dom节点,该事件处理器再调用所有用户绑定的事件处理函数。

 

20100427感悟:

事实上 Node.on 调用 Y.on ,而 Y argument 自 EventTarget ,则 相当于在 Y 上添加自定义事件,不同点在于,在Y上添加自定义事件的同时还在dom node上绑定事件当dom事件发生时fire自定义事件,自定义事件fire再调用我们的处理函数,又一次实现了自定义事件与dom事件的统一。

 

键:

 

var ek = Y.stamp(el),
key = 'event:' + ek + type,
cewrapper;
if (false === facade) {
  key += 'native';
}
if (capture) {
  key += 'capture';
}

                       
值 :

cewrapper,类型为 CustomEvent ,这样就和自定义事件完美融合在一起,将dom事件映射到了自定义事件,一个CustomEvent 对应于多个事件处理函数(listeners)
 
详见函数Y.Event._createWrapper: cewrapper 。

对单个元素单个事件的统一处理,事件发生后 cewrapper.fn 触发,然后再取Y.Env.evt.dom_map 为元素和该 cewrapper 关联的事件处理函数(listeners),再统一依次调用。

 

 

精妙的Y.augment :

 

保证augment后,new出来的示例,在运行相关augment方法时,之前augment来源构造器要在当前实例上运行且只运行一次!

 

关键源码解析:

Y.each(sProto, function(v, k) {
                replacements[k] = function() {
                    //任何一函数一运行,就把实例上的所有override函数置为 override来源的原方法 
                    for (i in sequestered) {
                        if (sequestered.hasOwnProperty(i) && (this[i] === replacements[i])) {
                            // Y.log('... restoring ' + k);
                            this[i] = sequestered[i];
                        }
                    }

                    
                    //保证只会运行一次,不管调用哪个override的方法,一旦调用,this[k]就不是replacements[i]了,
                    construct.apply(this, a);
                    return sequestered[k].apply(this, arguments);
                };

                if ((!wl || (k in wl)) && (ov || !(k in this))) {
               
                    if (L.isFunction(v)) {
                        //保留override来源的最原始方法
                        sequestered[k] = v;
                        //为了保证构造器运行且只运行一次,需要暂时替换一下
                        this[k] = replacements[k];
                    } else {
                  
                        this[k] = v;
                    }

                }

            }, newProto, true);

 

示例详解:

 

var comp=function(){};
Y.augment(comp,Y.EventTarget);
var two=new comp();

//EventTarget构造函数没有执行
console.log(two._yuievt);
//方法为暂时替代方法
console.log(two.on.toString());

//运行一次override函数,EventTarget构造函数作用在实例上,且实例上的所有方法复原			
two.on("ok",function(){});

//一切正常
console.log(two._yuievt);
console.log(two.on.toString());
 

 

 


总之一句话:yui任何一个函数的调用都很曲折,为了完美的架构以及桥梁承接以前略显陈旧的代码,yui3在性能上确实做出了不少的牺牲。

 

 

参考:

YUI3源码 以及 Luke Smith — Events Evolved

 

Satyen Desai — YUI3: Design Goals and Architecture

 

你可能感兴趣的:(AOP,jquery,浏览器,ext,yui)