YUI2.8相关核心源码浅解及学习笔记(二)

晚上接下去写event这一模块。。。这一篇可能要详细的讲讲YUI中的观察者模式

二、event模块

首先看下YUI封装的Event事件绑定机制:

最核心的一个函数便是addListener,这个函数除了第一个需要传入元素外其他形式参数的和jQ的bind一模一样,这里还是要注意第一个元素传入可以是id值数组
使用方法也比较的明了,注意YUI这里定义有一个简写为on的方法指向这个方法
var oElement = document.getElementById("flowg"); 
function callback(e) { alert("hello"); } 
YAHOO.util.Event.addListener(oElement, "click", callback);


    如上面说的这边的el也是可以传入一个数组引用的,下面的代码便是对于数组每个元素进行on方法迭代:
if ( this._isValidCollection(el)) {//判断是否为数组容器
                    var ok = true;
                    for (var i=0,len=el.length; i<len; ++i) {//迭代
                        ok = this.on(el[i], sType, fn, obj, override) && ok;
                    }
                    return ok;

           }
 

    这个绑定事件方法可以在DOM文档未加载完前调用,因为这个方法会自动判断是否加载完全,若否则会等待加载好了在执行,相应代码如下:
        else if (YAHOO.lang.isString(el)) {
                    var oEl = this.getEl(el);//这边的getEl就是ById方法的封装,可能是想保持模块间的松耦合,这边没有调用DOM模块的get方法
                    if (oEl) {//直接查找到的时候
                        el = oEl;
                    } else {
                        // 待载入完成之后再查找一次
                        this.onAvailable(el, function() {
                           YAHOO.util.Event.on(el, sType, fn, obj, override);
                        });

                        return true;
                    }
                }

接下去是绑定事件了,绑定事件的源码就不贴了,大致看了下也是用到了缓存数组存贮监听事件。

类似于jQ的unbind YUI也有,叫removeListener,把上面的callback解除绑定:

YAHOO.util.Event.removeListener("flowg", "click", callback);

最后一个参数不设置的话,就会吧该元素的所有click监听器全部解绑。

再看一个比较牛叉的方法 purgeElement(),把该元素的指定的所有监听函数全部移除。
// 移除改元素绑定的所有监听器函数 
YAHOO.util.Event.purgeElement(ele); 
// 移除该元素所有的子元素的绑定的监听器(这个务必慎用啊)
YAHOO.util.Event.purgeElement(ele, true); 
// 只移除该元素上click事件的监听函数
YAHOO.util.Event.purgeElement(ele, false, "click");


接下去又是jQ中万能的$的ready方法YUI版本要出场了。
这里有三个有点相似的方法:
onAvailable:当元素可用时触发,这个方法是有轮询机制的,默认状况下是10m内按照4000一次的频率轮询搜索元素;
onAvailable ( id , fn , obj , overrideContext , checkContent )这边最后的checkContent是查看子元素是否就绪,如果将它设为true则就是onContentReady这个方法了:
 onContentReady: function(p_id, p_fn, p_obj, p_override) {
                this.onAvailable(p_id, p_fn, p_obj, p_override, true);
            },

    而接下来的onDOMReady便是jQ的万能$的真正YUI版了,在DOM全部载入之后执行,系统会轮询检测DOM是否加载,当加载完毕后会使一个boolean类型Flag令为true,通知onDOMReady订阅者加载函数。这里同以前的一样也要注意,这边最后一个参数是是否用第二个参数作用域代替win作用域,常用与自建包中return的静态方法中:如下(get.js)

YAHOO.util.Event.onDOMReady( 
	    YAHOO.example.SiteExplorer.init,  //YAHOO.example.SiteExplorer中return公共静态方法
	    YAHOO.example.SiteExplorer,         //设置作用域 
	    true); //设置为true则是用上面的对象作为上下文

    下面是另外一个重点:CustomEvent这个自定义的事件。其中用到了观察者的设计模式
这边直接把官方的实例文档拿过来做一下注释:(感觉这个实例看懂了就基本这个类能够用了)
(function() {
	//首先new出一个自定义事件对象,取名为onSizeChange
	var onSizeChange = new YAHOO.util.CustomEvent("onSizeChange");
	var container = YAHOO.util.Dom.get("container");
	var resizer = YAHOO.util.Dom.get("resizer");
	
	function fnClick(e){
		
               //取得相关值
		var containerX = YAHOO.util.Dom.getX("container");
		var containerY = YAHOO.util.Dom.getY("container");
		var clickX = YAHOO.util.Event.getPageX(e);
		var clickY = YAHOO.util.Event.getPageY(e);
		//更改该元素css
		var containerPaddingX = parseInt(YAHOO.util.Dom.getStyle("container","padding-left"), 10);
		var containerPaddingY = parseInt(YAHOO.util.Dom.getStyle("container","padding-top"), 10);
		var newWidth = clickX - containerX - containerPaddingX;
		var newHeight = clickY - containerY - containerPaddingY;
		
	
		if ((newWidth > 0)||(newHeight > 12)) {

			if (newWidth < 0) {newWidth = 1;}
			if (newHeight < 12) {newHeight = 12;}
			YAHOO.util.Dom.get("resizer").innerHTML = "New size: " + newWidth + "x" + newHeight;
			YAHOO.util.Dom.setStyle("resizer", "width", newWidth + "px");
			YAHOO.util.Dom.setStyle("resizer", "height", newHeight + "px");
 
			//这边便是重点,发布一个消息,对于onSizeChange中注册的订阅者逐一的进行通知
			onSizeChange.fire({width: newWidth, height: newHeight});
		};
		
	}
	
	//注册监听器
	YAHOO.util.Event.addListener("container", 'click', fnClick);
 
        //这边有两个征订者函数
	fnSubscriberWidth = function(type, args) {
		var elWidth = YAHOO.util.Dom.get("subscriberWidth");
		var newWidth = args[0].width;
		YAHOO.util.Dom.setStyle(elWidth, "width", (newWidth + "px"));
		elWidth.innerHTML = ("My new width: " + newWidth + "px");
	}
	
	fnSubscriberHeight = function(type, args) {
		var elHeight = YAHOO.util.Dom.get("subscriberHeight");
		var newHeight = args[0].height;
		YAHOO.util.Dom.setStyle(elHeight, "height", (newHeight + "px"));
		elHeight.innerHTML = ("My new height: " + newHeight + "px");
	}	
	
        //指定函数订阅这个事件 
	onSizeChange.subscribe(fnSubscriberWidth);
	onSizeChange.subscribe(fnSubscriberHeight);

})();

    了解观察者模式对于这种结构的程序理解起来并不难。下面来看一下源码:
    首先是订阅消息:
subscribe: function(fn, obj, override) {
        /*此处省略一万行*/
        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, override) );//往订阅者队列中插入一个订阅者的实体
    },

    接下来是分发消息:
fire: function() {
        var len=this.subscribers.length;//取得队列长度
        var args=[], ret=true, i, rebuild=false;
        for (i=0; i<arguments.length; ++i) {//暂存消息信息
            args.push(arguments[i]);
        }
        //开始迭代分发消息给订阅者
        for (i=0; i<len; ++i) {
            var s = this.subscribers[i];
            if (!s) {
                rebuild=true;
            } else {
                if (!this.silent) {
                }

                var scope = s.getScope(this.scope);//取得域

                if (this.signature == YAHOO.util.CustomEvent.FLAT) {
                    var param = null;
                    if (args.length > 0) {
                        param = args[0];
                    }

                    try {
                        ret = s.fn.call(scope, param, s.obj);
                    } catch(e) {
                        this.lastError = e;
                    }
                } else {
                    try {
                        ret = s.fn.call(scope, this.type, args, s.obj);//这边便是调用订阅者的函数,函数传入形参可以看都是type,arges,obj三个参数
                    } catch(ex) {
                        this.lastError = ex;
                    }
                }
                if (false === ret) {
                    if (!this.silent) {
                    }

                    //break;
                    return false;
                }
            }
        }


        return true;
    },

     大概的模式就是这样,然后还有个与之对应的方法,就是取消订阅者unsubscribe这个方法,方法内执行的是将订阅者队列中的对应函数对象移除。
    
     小结下:这篇写的也不是很详细,对有些代码的实现感到还是疑惑,不过YUI中的自定义事件相当经典,可以完全制造出基于逻辑的事件监听,更加符合面向对象的思想,也难怪后来的Ext基本对于此事件处理完全继承下来了~~
    
     有时间下一篇写一下ajax模块~~

你可能感兴趣的:(Yahoo,yui)