欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-06 08:09:06
...
晚上接下去写event这一模块。。。这一篇可能要详细的讲讲YUI中的观察者模式

[b]二、event模块[/b]

首先看下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这个方法,方法内执行的是将订阅者队列中的对应函数对象移除。

[b]小结下:这篇写的也不是很详细,对有些代码的实现感到还是疑惑,不过YUI中的自定义事件相当经典,可以完全制造出基于逻辑的事件监听,更加符合面向对象的思想,也难怪后来的Ext基本对于此事件处理完全继承下来了~~[/b]

有时间下一篇写一下ajax模块~~
相关标签: Yahoo YUI