暂时放下dojo,搞搞YUI。

感觉YUI还是蛮有前景的。
首先yahoo在后支持;
mail list也比较活跃,但好象高人关注的不多;
出现时间不常,参考了太多开源类库如prototype.js及扩展项目,dojo....;
项目测试做的不错(yahoo用了它的不少);
太多的灵感(yahoo中界面,用户交互设计高人应该提了不少建议)
容易上手(代码写的比较累赘,可能是0.10.0版本吧);

不敢再与其它类库比较了,怕招骂。呵。总之还是我的那个观点,javascript代码太容易抄袭了,所以类库的可”重构性“很是重要。YUI做的还行吧。

现在切入正题
一、dom.js可能这部分与prototype.js某些功能差不多,但实现感觉比prototype.js更好些(个人观点,别咂我哦)
  1、通过id,className,TagName等返回DOM元素的方法。getElementsBy (<Function> method, <String> tag, <String/HTMLElement> root) 看看这个方法很有意思。你可以通过这个方法定制你取的dom元素的方法。
     getElementsBy: function(method, tag, root) {
         tag = tag || '*';
         root = this.get(root) || document;
        
         var nodes = [];
         var elements = root.getElementsByTagName(tag);
        
         if ( !elements.length && (tag == '*' && root.all) ) {
            elements = root.all; // IE < 6
         }
        
         for (var i = 0, len = elements.length; i < len; ++i)
         {
            if ( method(elements[i]) ) { nodes[nodes.length] = elements[i]; }
         }

         return nodes;
      },
  2、修改dom元素的className.
     无非是增,删,改,查。注意 YUI中可以传入id或dom的数组来处理。通过匿名函数来实现。绝对经典。
   详细看
batch: function(el, method, o, override) {
         el = this.get(el);
         var scope = (override) ? o : window;
        
         if (!el || el.tagName || !el.length)
         { // is null or not a collection (tagName for SELECT and others that can be both an element and a collection)
            return method.call(scope, el, o);
         }
        
         var collection = [];
        
         for (var i = 0, len = el.length; i < len; ++i)
         {
            collection[collection.length] = method.call(scope, el[i], o);
         }
        
         return collection;
      },
3、直接对DOM元素的style的修改
   如果修改dom.style细粒度属性。className就不合适了。还好提供了这些方法。并且跨浏览器支持的不错,很多属性我都不知道,看代码才明白各个浏览器对css支持有不同,如property == 'opacity' && el.filters

   也用batch支持数组方式。
YAHOO.util.Dom.setStyle(["div1","div2","div3"], "color","red");
4、对dom元素位置和大小的函数
对于偶喜欢摆弄webgis,google maps之类的当然最喜欢这部分了。
可以得到或修改dom元素的x,y。YUL的animation、dragdrop等大量用到这个东西。当然这部分也做了大量跨浏览器支持。
对于DOM的大小,YUI定义了个YAHOO.util.Region包,也就是个矩形,定义了contains(包含),intersect(相交方法)。呵呵,和prototype.js中的within,overlap差不多。  其实用这个函数实现google个性化定义的拖是个好不错。
5、其它方法
getViewportHeight ()   getDocumentHeight   不知道有什么不同,待偶查查资料去。
getViewportWidth ()   getDocumentWidth
inDocument  是否document对象
isAncestor: function(haystack, needle) 检查dom对象是否是另一个对象的父节点
...................

二、event.js
关于注册事件的问题我也写过不少,YUI实现的是不错的,通过CustomEvent也可以模拟实现AOP的方法拦截。当然dojo的实现还是老大。
主要分为两部分。
1、事件注册
YAHOO.util.Event.addListener: function(el, sType, fn, oScope, bOverride);
参数分别是: dom的ID或元素本身;类型(click,mouseover等);函数;谁调用这个函数;是否覆盖

看例子,注意最后两个参数,只有在bOverride为true时才有效。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>test</title>
<script type="text/javascript" src="../../build/yahoo/yahoo.js"></script>
<script type="text/javascript" src="../../build/event/event.js"></script>
<script type="text/javascript" src="../../build/dom/dom.js"></script>
<script type="text/javascript">
var name="window.name";
var Fun={
    name : "funName",
 doClick: function(){
       alert(this.name);
 }
}
var init = function() {
   YAHOO.util.Event.addListener(test, 'click', Fun.doClick);
   YAHOO.util.Event.addListener(test, 'click', Fun.doClick,Fun,false);
   YAHOO.util.Event.addListener(test, 'click', Fun.doClick,Fun,true);
   YAHOO.util.Event.addListener(test, 'click', Fun.doClick,window,true);
};

YAHOO.util.Event.addListener(window, 'load',init);
</script>
</head>
<body>
<div id="test" name="dom name">
   谁敢点我
</div>
</body>
</html>

小TIP:yahoo的事件注册支持多个dom元素的事件注册,只要第一个参数是 dom对象的数组就可以了。
      也支持延迟注册,也就是你在dom元素还没有加载的时候注册事件,但有个条件,第一个参数必须是字符串(dom的id),这里就不支持多个元素的注册了。  YUI会在window.onload方法里把所有延迟注册的事件注册了(太绕了)。

2、CustomEvent,Subscriber
  一个观察者模式的javascript的实现,要想用好,难度不小,yahoo官网提供的例子也极度白痴。但在YUI的animation,AutoComplete等里面应用了这个玩意,很有创意。在控件内部定义的很多CustomEvent,当控件状态改变时,触发CustomEvent里面的Subscriber方法。有点AOP的感觉。
  感觉这类传统c/s的设计模式用javascrit来实现对于我们普通开发者来说没什么好处,反而让代码更加难懂,类库里面用用就得了,。无论什么地方用,把ajax变成当成c/s架构的变成思想是我们应该提前树立的。
  我也只能通过例子说说定制事件了;下面代码(拷贝到html可以直接运行ie,ff下测试通过)是一个简单的AOP实现,象这种弱类型,参数可以随便变化的语言实现类似AOP的功能是很尴尬的。就当练手的。

    开发ajax时,把浏览器当成桌面开发,那时,观察者,MVC就很实用了.


<body>
<div id="log"></div>
</body>
<SCRIPT LANGUAGE="JavaScript">
function log(msg){
    var obj=document.getElementById("log");
 obj.innerHTML+=msg+"<br>";//你们可别这么写啊
}
var YAHOO={};
YAHOO.util={};
YAHOO.util.CustomEvent = function(type, oScope) {
    this.type = type;
    this.scope = oScope || window;
    this.subscribers = [];
    if (YAHOO.util.Event) {
        YAHOO.util.Event.regCE(this);
    }
};

YAHOO.util.CustomEvent.prototype = {
    subscribe: function(fn, obj, bOverride) {
        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
    },
    unsubscribe: function(fn, obj) {
        var found = false;
        for (var i=0, len=this.subscribers.length; i<len; ++i) {
            var s = this.subscribers[i];
            if (s && s.contains(fn, obj)) {
                this._delete(i);
                found = true;
            }
        }

        return found;
    },
    fire: function() {
        for (var i=0, len=this.subscribers.length; i<len; ++i) {
            var s = this.subscribers[i];
            if (s) {
                var scope = (s.override) ? s.obj : this.scope;
                s.fn.call(scope, this.type, arguments, s.obj);
            }
        }
    },
    unsubscribeAll: function() {
        for (var i=0, len=this.subscribers.length; i<len; ++i) {
            this._delete(i);
        }
    },
    _delete: function(index) {
        var s = this.subscribers[index];
        if (s) {
            delete s.fn;
            delete s.obj;
        }

        delete this.subscribers[index];
    }
};
YAHOO.util.Subscriber = function(fn, obj, bOverride) {
    this.fn = fn;
    this.obj = obj || null;
    this.override = (bOverride);
};
YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
    return (this.fn == fn && this.obj == obj);
};

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////

var ProxyFunction=function(fn,scope){
   this.fn=fn;
   this.scope=scope||window;
   this.beforeEvent=new YAHOO.util.CustomEvent("beforeEvent",this.scope);
   this.afterEvent=new YAHOO.util.CustomEvent("afterEvent",this.scope);
}
ProxyFunction.prototype.addBefore=function(fn, obj){
   this.beforeEvent.subscribe(fn, obj,true);
}
ProxyFunction.prototype.addAfter=function(fn, obj){
   this.afterEvent.subscribe(fn, obj,true);
}
ProxyFunction.prototype.execute=function(){
    this.beforeEvent.fire();
    var ret=this.fn.apply(this.scope, arguments);//我这里面保证arguments为fun被代理函数的参数列表
 log("execute......");
 log("execute after 前 ret="+ret);
 var temp={result:ret};//为了修改执行结果......
    this.afterEvent.fire(temp);
 return temp.result;
}
var Logic={
    name: "Logic private value",
    fun : function (p){
     log("被代理方法访问this.name="+this.name);
        return "fun "+p+" execute!";
    }
}
function Interceptor(){
    this.name="Interceptor  private value";
}
Interceptor.prototype.before=function(){
    log("before...... this.name="+this.name);
 log("before...... arguments[0]="+arguments[0]+" arguments[1]="+arguments[1]+" arguments[2]="+arguments[2]+" arguments[3]="+arguments[3]);
 log("before...... arguments[2]="+arguments[2]+" 为addBefore/addAfter中最后一个参数");
    log("before......");
}
Interceptor.prototype.after=function(){
    log("after......this.name="+this.name);
 log("after......arguments[1]="+arguments[1][0] +"  可以在这修改返回的结果");
 arguments[1][0].result="修改结果";
    log("after......");
}

var funProxy=new ProxyFunction(Logic.fun,Logic);//参数[0] 需要代理的函数 参数[1] 执行这个函数的对象
var myInterceptor=new Interceptor();//新建拦截器

funProxy.addBefore(myInterceptor.before,window);//注意第三个参数
funProxy.addBefore(myInterceptor.before,myInterceptor);
funProxy.addAfter(myInterceptor.after,Logic);
var result=funProxy.execute("参数");
log(result);
</SCRIPT>

待续其它................