使用Dojo的Ajax应用开发进阶教程,第8部分: Dijit开发最佳实践2011-01-21 IBM 成富Dijit 组件(widget)是 Dojo 提供的图形用户界面组件库。它提供了 Ajax 应用开发中会用到的常用组件,可以帮助开发人员快速的构建 Ajax 应用。本文并不会介绍 Dojo 默认提供的组件,而是侧重于介绍 Dijit 组件的编程模型和最佳实践,其目的是帮助开发人员更好的开发自己的 Dijit 组件。下面首先对 Dijit 做概要介绍。Dijit 概述Dijit 组件的存在是 Dojo 框架区别于其它 JavaScript 框架的一个重要特性。在桌面应用开发中,开发人员大量使用图形用户界面组件库来提高开发效率。而在 Web 应用开发中,HTML 语言本身仅提供了少数基本的控件,如按钮、单选框、复选框、文本输入框和下拉列表等。而对于在 Web 应用开发中常见的一些复杂组件,如对话框、菜单、工具栏、进度条、富文本编辑器和树等,并没有提供原生的支持。在这种情况下,开发人员往往需要自己开发这样的复杂组件,这就造成了更长的开发周期和更高的开发和维护的成本。Dojo 提供了一个种类多样的组件库。开发人员只需要简单的定制就可以在自己的应用中使用这些组件。除此之外,Dojo 还提供了完善的组件编程模型。如果默认提供的组件都不能满足需求,可以自己来开发所需的组件。遵循这个统一的编程模型,会比从头开始创建组件要容易得多。有了组件的概念之后,开发人员在设计 Web 应用的时候,就可以从比较高的抽象层次来对应用的各个部分进行划分。定义好清晰的组件接口之后,团队成员就可以各司其职,并行开发,从而提高开发效率。在开发 Dijit 组件的时候,需要注意下面几个基本的问题。组件的粒度问题。一般来说,功能比较复杂的组件不利于复用,也不利于团队开发时的分工合作。但是过多小组件在页面上的时候,会消耗比较多的系统资源,影响性能。而性能对 Web 应用来说是一个非常重要的因素。因此需要进行一定的权衡。比较好的做法是从较大的组件开始,当发现存在代码重复的时候,再把重复的代码提取出来,重构成新的组件。这样就把划分成小组件的决策推迟到了真正需要的时候,避免过度设计。组件的接口问题。组件的接口定义了代码中的其它部分如何使用该组件。一般来说,组件可以提供三类的接口:公共属性、公共方法和事件绑定点。公共属性指的是组件提供的可以公开访问的简单数据类型属性。一般在创建组件的时候使用,用来对组件进行定制;公共方法指的是可以公开访问的 JavaScript 方法。一般在组件创建完成之后使用,用来改变组件的行为;事件绑定点是组件暴露出来的占位方法。一般由组件使用者通过 dojo.connect()来绑定到该方法上。组件使用该方法来通知使用者其内部状态的变化。这类方法一般以 on作为名称前缀。开发人员应该根据需要定义合适的接口,避免一些不好的实践。比如公共属性的值在组件创建之后,一般不推荐使用者设置其值。如果设置该属性的值是一个合理的场景的话,最好提供相应的公共方法,并以文档的形式告诉使用者正确的用法。组件之间的交互问题。组件之间如果需要相互通讯的话,最好使用组件的对象引用来完成。比如某个组件在创建另外一个组件的时候,可以把自己的对象引用作为参数传递给其创建出来的组件。后者就可以使用此对象引用来调用前者的方法。另外一种做法是通过 dojo.publish()和 dojo.subscribe()方法来完成。这种做法的使用比较简单,可以避免层次较深的对象引用传递。不好的地方是组件之间的关联关系不够清晰,也比较难维护。推荐的做法是优先使用第一种方式。上面对开发 Dijit 组件的一些通用问题进行了讨论。下面开始介绍 Dijit 组件的编程模型。在编程模型的介绍过程中,会穿插介绍相关的最佳实践。首先从 Dijit 组件的核心类 dijit._Widget开始。dijit._Widgetdijit._Widget是所有 Dijit 组件的父类。Dijit 默认提供的组件以及自己开发的组件都需要继承自此类。dijit._Widget所提供的方法涉及组件的生命周期、属性设置和获取、事件处理和其它辅助功能等。深入了解该类的这些方法的用法和实现细节,是开发自己的 Dijit 组件的基础。下面分别对 dijit._Widget提供的方法进行分类讨论。组件生命周期dijit._Widget提供了对组件生命周期的完整管理,包括组件的创建和销毁。Dijit 组件的生命周期管理在实现的时候,使用了模板方法(Template Method)设计模式。dijit._Widget类的 create()方法定义了 Dijit 组件创建时的生命周期的默认模板。该方法会在合适的时机调用模板中包含的其它方法。这些不同的方法构成了组件生命周期中的各个阶段。开发自己的组件的时候,可以覆写其中的某些方法,从而在感兴趣的阶段添加自己的处理逻辑。开发人员也可以覆写 create()方法来提供一套完全不同的生命周期实现。不过这种做法风险太大,不建议使用。绝大多数情况下,覆写默认模板提供的方法就足够了。dijit._Widget中定义的组件生命周期中的创建阶段如 图 1 所示。图 1. Dijit 组件创建过程