最近因为忙于YUI2到YUI3的迁移,没时间更新博客。现在闲暇一些,觉得似乎写一点自己对于YUI3的理解再合适不过。
主要内容有以下几点:
全局命名空间
YUI3为了保持向前兼容,采用了新的全局命名空间YUI。新的命名空间与YUI2的全局命名空间YAHOO最大的不同就是:YUI是一个构造函数,而且是一个无论如何也返回一个实例的构造函数。
改变一切的模块
YUI2时代,一般都是将某方面的全部方法写在统一的命名空间下,例如DOM相关的方法均在YAHOO.util.Dom,在需要使用这些方法时我们直接调用即可。YUI2真正体现了基础方法库(function library)这样一种定位。
YUI3最大的变化和进步在于,它采用了革新性的底层组织方式,其核心就是模块(module)。在YUI3中,每个方法不再属于某个文件、某个命名空间,而是属于某个模块。每个模块代表一个独立的功能,例如DOM、Event等。下面是一个简单的例子:
YUI.add('new-module', function(Y) { Y.sayHelloWorld = function(id) { var el = Y.DOM.byId(id); Y.DOM.set(el, 'innerHTML', 'Hello, world!'); }; }, '1.0.0', { requires:['dom'] } );
通过调用YUI构造器本身的add静态方法,我们声明了一个新的模块,模块的名称为new-module,模块为YUI的实例Y挂载了sayHelloWorld方法,因为这个方法使用了dom模块的方法byId,所以要在add的第四个参数中标明new-module模块依赖于dom模块。
添加模块的目的是为了使用它,下面给出调用new-module的示例:
// html <div id="entry"></div> // js YUI().use('new-module', function(Y) { Y.sayHelloWorld('entry'); // <div id="entry">Hello, world!</div> });
通过调用YUI实例的use方法,在列出模块名称之后,我们可以随意使用它们挂载的方法。需要提醒的是,YUI的loader会发现’new-module’模块依赖于dom模块,然后它去check当前页面是否已经有dom模块,没有的话则动态加载。
总结一下,发现模块为我们带来了这些好处:
- 遗弃domready:在YUI2中,页面通常要在domready之后调用js方法。在YUI3中可以省掉这一步了,因为只有在所有需要的模块都加载完毕后才会调用js方法,而我们通常都是在<body>最后面引入js,此时dom基本已经就绪。当然,YUI3仍然提供domready事件监听方法。
- 沙箱(Sandbox):在使用模块时,我们只能调用这些模块以及它们依赖的所有模块给YUI实例挂载的方法。这种机制可以限定你的代码在一定范围内执行,而不是肆意妄为。
- 自动加载:我们不必再手动添加<script>标签引入js,更不必为js文件间的顺序依赖问题揪心,YUI的loader会为你摆平,而它的依据正是各个模块中的requires参数。
- 开发框架(Framework):基于这种方法的声明/调用机制,YUI3更像一个js开发框架而不仅仅是一个方法库。我们可以将自己需要的功能作为一个个模块,可以细分为全局通用模块、分站通用模块、分站应用模块等层级。YUI3为此提供了非常简便的接口。
我觉得用这样一句话形容模块对于YUI的意义最好不过:“Inception”中Cobb所说的“a very simple idea that changed everything”。
至于模块如何设计、如何分级,将是一个非常有挑战的问题。我准备在适当的时间做下经验总结,现在暂不展开讲。
Combo
在YUI3框架中,每个模块都对应一个独立的js文件(也有所有子模块组成一个模块的特殊情况,在此不细较),日常开发中,往往需要动态加载大量的模块,造成http请求数较YUI2时代翻几番。众所周知的是,在yui团队的Best Practices for Speeding Up Your Web Site一文中提到的第一条准则就是降低http请求数。如果模块化带来的更小粒度更大规模的js文件使得页面加载速度更慢,那么它所有的优势将不再具有吸引力。好消息是,YUI团队很好的解决了这一问题,他们引入了combo的思想,即使用服务器端技术,收到包含多个js文件请求的url之后,合并这些文件为一个大文件返回。
关于Combo的具体文章,可以参考在服务端合并和压缩JavaScript和CSS文件。
链式调用
jQuery因为方便的链式调用而风靡全球,其write less do more的核心理念也随之深入人心。欣喜的是,YUI团队汲取了这一优点,在YUI3中引入了新的Node/NodeList对象,并取代DOM成为YUI3 Core。这一变化无疑将增加YUI3代码的书写效率,成为有一个显著的加分点。
更广泛的自定义事件
YUI3提供了简约而强大的custom event:更加dom-like的调用方法,可以冒泡,可以经历各个事件阶段,可以定义默认动作,可以设定传播范围是模块内部还是模块之间等等。目前对于这部分仍然不甚熟悉,有兴趣的朋友可以参考Luke Smith做的这个讲座。
一些问题
YUI3并不完美,目前为止仍然存在一些问题,列举如下:
- 文档仍然不够详尽,很多时候只能去查源代码。例如YUI2中getRegion方法在YUI3中的对应方法为node.get(‘region’)。
- Node实例只能通过get方法取id,value等自身属性,可以参考jQuery采用更简洁的api,例如val(), height(), text()等。
- 得到一个定制的YUI实例时,需要将自己开发的模块的path、requires信息作为参数传进去,而在声明自定义模块时仍需要设定requires,这种冗余设计是可以做优化的。
- 使用Node操作Form时非常繁琐。例如要获取一个text表单项只能使用ndForm.one(‘input[name="xxx"]‘),而不能ndForm.get(‘xxx’)。
- 在存在name=”id”项的表单中,存在因Y.Selector.test失效而产生的各种问题。例如Y.one(‘#input-id’).ancestor(‘form’)取不到等等。
- 没有公开的Form的serialize方法。
ok,这就是我对YUI3的一些浅薄见解。欢迎讨论和指正。随着经验的不断积累,后续会奉上更深入的一些分析。