Dijit 组件(widget)是 Dojo 提供的图形用户界面组件库。它提供了 Ajax 应用开发中会用到的常用组件,可以帮助开发人员快速的构建 Ajax 应用。本文并不会介绍 Dojo 默认提供的组件,而是侧重于介绍 Dijit 组件的编程模型和最佳实践,其目的是帮助开发人员更好的开发自己的 Dijit 组件。下面首先对 Dijit 做概要介绍。
Dijit 组件的存在是 Dojo 框架区别于其它 JavaScript 框架的一个重要特性。在桌面应用开发中,开发人员大量使用图形用户界面组件库来提高开发效率。而在 Web 应用开发中,HTML 语言本身仅提供了少数基本的控件,如按钮、单选框、复选框、文本输入框和下拉列表等。而对于在 Web 应用开发中常见的一些复杂组件,如对话框、菜单、工具栏、进度条、富文本编辑器和树等,并没有提供原生的支持。在这种情况下,开发人员往往需要自己开发这样的复杂组件,这就造成了更长的开发周期和更高的开发和维护的成本。
Dojo 提供了一个种类多样的组件库。开发人员只需要简单的定制就可以在自己的应用中使用这些组件。除此之外,Dojo 还提供了完善的组件编程模型。如果默认提供的组件都不能满足需求,可以自己来开发所需的组件。遵循这个统一的编程模型,会比从头开始创建组件要容易得多。有了组件的概念之后,开发人员在设计 Web 应用的时候,就可以从比较高的抽象层次来对应用的各个部分进行划分。定义好清晰的组件接口之后,团队成员就可以各司其职,并行开发,从而提高开发效率。
在开发 Dijit 组件的时候,需要注意下面几个基本的问题。
dojo.connect()
来绑定到该方法上。组件使用该方法来通知使用者其内部状态的变化。这类方法一般以 on
作为名称前缀。开发人员应该根据需要定义合适的接口,避免一些不好的实践。比如公共属性的值在组件创建之后,一般不推荐使用者设置其值。如果设置该属性的值是一个合理的场景的话,最好提供相应的公共方法,并以文档的形式告诉使用者正确的用法。dojo.publish()
和 dojo.subscribe()
方法来完成。这种做法的使用比较简单,可以避免层次较深的对象引用传递。不好的地方是组件之间的关联关系不够清晰,也比较难维护。推荐的做法是优先使用第一种方式。
上面对开发 Dijit 组件的一些通用问题进行了讨论。下面开始介绍 Dijit 组件的编程模型。在编程模型的介绍过程中,会穿插介绍相关的最佳实践。首先从 Dijit 组件的核心类 dijit._Widget
开始。
dijit._Widget
是所有 Dijit 组件的父类。Dijit 默认提供的组件以及自己开发的组件都需要继承自此类。dijit._Widget
所提供的方法涉及组件的生命周期、属性设置和获取、事件处理和其它辅助功能等。深入了解该类的这些方法的用法和实现细节,是开发自己的 Dijit 组件的基础。下面分别对 dijit._Widget
提供的方法进行分类讨论。
dijit._Widget
提供了对组件生命周期的完整管理,包括组件的创建和销毁。Dijit 组件的生命周期管理在实现的时候,使用了模板方法(Template Method)设计模式。dijit._Widget
类的 create()
方法定义了 Dijit 组件创建时的生命周期的默认模板。该方法会在合适的时机调用模板中包含的其它方法。这些不同的方法构成了组件生命周期中的各个阶段。开发自己的组件的时候,可以覆写其中的某些方法,从而在感兴趣的阶段添加自己的处理逻辑。开发人员也可以覆写 create()
方法来提供一套完全不同的生命周期实现。不过这种做法风险太大,不建议使用。绝大多数情况下,覆写默认模板提供的方法就足够了。dijit._Widget
中定义的组件生命周期中的创建阶段如 图 1 所示。
如 图 1 所示,创建 Dijit 组件时的过程中包含如下几个步骤:
postMixInProperties()
方法被调用。buildRendering()
方法被调用。postCreate()
方法被调用。startup()
方法。
图 1 中给出了 4 个方法的名称,其中椭圆形中的 postMixInProperties()
、buildRendering()
和 postCreate()
是 dijit._Widget
提供的组件生命周期中的扩展点。自己开发的组件应该通过覆写这些方法来实现自己的逻辑。圆角矩形中的 startup()
方法并不是创建过程中的一部分,需要在 Dijit 组件创建完成之后显式的调用。下面对这 4 个方法进行详细的说明。
postMixInProperties()
:在创建 Dijit 组件的时候,可以通过参数来传入一个包含各种属性的 JavaScript 对象。这些属性被混入到 Dijit 组件中,在代码中可以通过 this
来引用。当混入完成之后,在创建组件的界面之前,可能还需要执行一些处理。这些处理的逻辑可以添加在 postMixInProperties()
方法中。buildRendering()
:该方法用来创建 Dijit 组件的用户界面,即 DOM 节点。该方法完成之后,Dijit 组件的 this.domNode
指向的是创建完成的 DOM 节点。postCreate()
:当 Dijit 组件的 DOM 节点创建完成之后,此方法被调用。需要注意的是,这个时候组件的 DOM 节点可能还没有被添加到当前页面文档树中。startup()
:当 Dijit 组件及其子组件被创建完成并添加到当前页面文档树中之后,显式的调用此方法。该方法对于那些包含子组件的 Dijit 组件来说非常有用,可以用来控制子组件和进行布局。startup()
方法只需要调用一次即可。调用完成之后,组件的属性 _started
的值为 true
,可以用来判断 startup()
方法是否已经被调用过。
与创建 Dijit 组件对应的组件的销毁过程。销毁过程比较复杂,涉及到 5 个方法,如 图 2 所示。图 2 中的箭头表示的是方法之间的调用关系。
如 图 2 所示,最常用的销毁一个 Dijit 组件的方法是 destroyRecursive()
。该方法用来销毁一个 Dijit 组件及其包含的子组件。该方法会首先调用 destroyDescendants()
方法来销毁子组件。由于子组件也可能包含自己的子组件,destroyDescendants()
也会调用 destroyRecursive()
方法来删除其子组件,从而形成一个递归的销毁过程。当子组件销毁完成之后,destroyRecursive()
会调用 destroy()
方法来销毁自己。destroy()
方法会首先调用 uninitialize()
,接着执行内部的清理工作,最后调用 destroyRendering()
方法来销毁组件的 DOM 节点。需要注意的是,destroy()
方法会销毁在 Dijit 组件模板中定义的子 Dijit 组件。这 5 个方法中除了 uninitialize()
之外的其它 4 个方法,都有一个参数 preserveDom
用来表明是否保留 Dijit 组件的 DOM 节点,不过对从模板创建出的 Dijit 组件无效。
在深入理解了 Dijit 组件的生命周期之后,就可以更好的利用 Dijit 库提供的支持来开发自己 Dijit 组件。下面介绍一些与组件生命周期相关的最佳实践。
postCreate()
方法中添加组件相关的处理逻辑即可。如果需要添加与 DOM 节点大小和位置相关的逻辑,应该放在 startup()
方法中,并要求组件的使用者显式调用。在覆写方法的时候,要通过 this.inherited(arguments);
来调用 dijit._Widget
类的原始方法。uninitialize()
方法中,并且只包含当前组件相关的逻辑,不需要考虑子组件。destroyRecursive()
方法会负责处理子组件的销毁。destroyRecursive()
来销毁一个 Dijit 组件。这样可以确保子组件总是被正常销毁,避免内存泄露。destroyRecursive()
、destroyDescendants()
、destroy()
和 destroyRendering()
等 4 个方法。这 4 个方法封装了完整的 Dijit 组件销毁逻辑。一般来说,覆写 uninitialize()
方法就已经足够了。
Dijit 组件中可能包含各种不同的属性,允许使用者对这些属性进行获取和设置。下面以一个显示电子邮件地址的 Dijit 组件来进行说明。该组件应该允许使用者获取和设置显示的电子邮件地址。一般来说,需要提供 getEmail()
和 setEmail(email)
两个方法来实现。另外,为了防止暴露邮件地址,一般需要用特殊的字符替换掉电子邮件地址中的“@”符号,如 admin@example.org
被替换成 admin#example.org
。这样的话就需要提供另外的两个方法。为了简化属性的获取和设置操作,dijit._Widget
类中提供了 attr(name, value)
方法来统一完成属性的获取和设置。当只传入一个参数的时候,如果该参数是一个字符串,则表示获取属性的值;如果参数是一个 JavaScript 对象,则用该对象中的属性和值来设置组件的属性。当传入两个参数的时候,两个参数分别表示为属性的名称和要设置的值。对于示例 Dijit 组件来说,可以通过 attr("email", "alex@example.com")
来设置要显示的电子邮件地址。
对于 Dijit 组件自定义的属性,默认情况下是保持在组件对象实例中的。attr()
方法直接读取和设置组件对象中对应属性的值即可。除此之外,还可以通过 attributeMap
来提供从属性到 DOM 节点之间的映射。即通过改变属性的值,就可以修改 DOM 节点。如果希望在获取和设置属性的时候添加额外的处理逻辑,则需要提供满足命名规范的对应方法。该命名规范是在首字母大写的属性名称上添加特定的前缀和后缀。如对于属性 email
来说,自定义的获取和设置属性的方法分别是 _getEmailAttr()
和 _setEmailAttr()
。自定义方法的优先级高于默认的方法。attr()
会首先尝试在 Dijit 组件对象中查找是否存在自定义的方法。代码清单 1 中给出了一个获取和设置属性的示例。
dojo.declare("emailDisplayer", dijit._Widget, { replaceString : "", _setEmailAttr : function(value) { if (!value) { return; } var originalValue = value; var displayValue = value; if (this.replaceString) { displayValue = displayValue.replace(/@/, this.replaceString); } this.domNode.innerHTML = displayValue; this.email = originalValue; } }); var n = dojo.create("div", null, dojo.body()); var displayer = new emailDisplayer({}, n); displayer.attr("replaceChar", "#"); displayer.attr("email", "alex@example.org"); displayer.attr("email"); |
如 代码清单 1 所示,Dijit 组件 emailDisplayer
定义了两个属性 email
和 replaceString
。对于属性 email
提供了自定义的设置方法 _setEmailAttr()
。对于属性 replaceString
则使用的是默认的实现。
对于统一的 attr()
方法接口和自定义的属性获取和设置方法,Dijit 组件既可以方便使用者的使用,又给了开发人员足够的灵活性。在组件开发中,尽量避免提供 Dijit 组件自己的属性获取和设置方法,而是充分利用 Dijit 组件提供的支持。
除了上面提到的两类方法之外,dijit._Widget
还提供了其它一些方法。
connect()
方法来绑定事件处理方法。其好处是在 Dijit 组件被销毁的时候,会自动调用 disconnect()
来取消事件绑定。subscribe()
方法来监听事件通知。其好处是在 Dijit 组件被销毁的时候,会自动调用 unsubscribe()
来取消事件监听。
在介绍完 dijit._Widget
之后,下面介绍另外一个核心类 dijit._Templated
。
在介绍 Dijit 组件的生命周期的时候,提到过 dijit._Widget
类中的 buildRendering()
方法用来创建 Dijit 组件的用户界面。如果通过 DOM 操作来创建用户界面的话,一般来说会比较复杂,维护起来也比较麻烦。dijit._Templated
提供了一种从 HTML 模板中创建 Dijit 组件用户界面的方式。dijit._Templated
一般是作为一个混入类的方式来使用的。它提供了自己的 buildRendering()
用来从模板字符串或是文件中创建 DOM 节点。在使用 dijit._Templated
的时候,有下面几点需要注意。
dojo.declare()
方法定义新的组件的时候,dijit._Widget
需要作为基类,而 dijit._Templated
只能作为混入类。也就是说在父类声明中,dijit._Widget
需要作为第一个出现;否则的话会出现错误。templateString
和 templatePath
两种方式来指定所使用的模板。从 Dojo 1.4 开始,建议使用 templateString
来指定模板字符串。不过在 Dijit 组件开发过程中,把模板存放在单独的 HTML 文件中更加便于开发和调试。因此在开发过程中可以使用 templatePath
。在发布的时候,则需要通过 Dojo 的构建过程把 HTML 文件的内容内联到组件代码中,通过 templateString
来表示。widgetsInTemplate
的值为 true
可以声明该 Dijit 组件中包含其它的组件。这些包含的组件在 destroy()
方法中会被销毁。
在模板中可以使用 dojoAttachPoint
和 dojoAttachEvent
两个特殊的 DOM 节点的属性。dojoAttachPoint
属性的值被转换成组件对象中的一个属性的名称,该属性的值是当前的 DOM 节点。dojoAttachEvent
属性的值被转换成通过 dojo.connect()
完成的事件处理绑定。如 <div dojoAttachPoint="myDiv" dojoAttachEvent="onclick:show" />
声明了该 DOM 节点可以在组件对象中通过 myDiv
来引用,点击该节点会调用 show()
方法。这两个属性的存在带来了编程上的简便。在组件对象的方法中,如果需要引用某个 DOM 节点的话,一般需要通过 DOM 查询或是 dojo.query()
来完成,这样的话会比较繁琐。通过 dojoAttachPoint
就避免了查询操作,使用起来更加简单。如果需要绑定事件处理的话,使用 dojoAttachEvent
就免去了对 dojo.connect()
方法的显式调用。不过使用这两个属性的话,会造成变量的声明和使用在不同的地方,会在一定程度上影响代码的可读性。比较好的实践如下:
dojoAttachPoint
声明的属性和一般的属性,最好为 dojoAttachPoint
声明的属性名称添加统一的后缀,如 Node
或是 Container
。其好处是开发人员在发现带某个后缀的属性时,会明白要去模板中查找相关的声明。dojoAttachPoint
和 dojoAttachEvent
,也可以统一使用 DOM 查询和 dojo.connect()
。最好不要两种方式混用。项目开发团队应该根据团队的意见,制定出相关的代码编写规范。
在介绍完 dijit._Templated
之后,下面介绍另外一个核心类 dijit._Container
。
有些 Dijit 组件是作为其它组件的容器而存在的,如与页面布局相关的组件。作为容器的组件需要对其包含的子组件进行管理,包括查询、添加和删除子组件等。dijit._Container
混入类提供了这些管理子组件的功能,自己开发的组件可以直接混入此类。dijit._Container
所提供的方法如下所示:
addChild(widget, insertIndex)
:该方法用来添加一个新的子组件到给定位置上。参数 widget
表示的是子组件,insertIndex
表示的是添加的位置。removeChild(widget)
:该方法用来移除一个子组件。参数 widget
既可以是子组件的引用,也可以是子组件的序号。getChildren()
:该方法返回一个包含所有子组件的数组。hasChildren()
:该方法用来判断是否包含子组件。getIndexOfChild(widget)
:该方法用来返回一个子组件的序号。
通过上面提到的这些方法,就可以完成对子组件的管理。在使用 dijit._Container
的时候,有下面几点需要注意:
dijit._Container
中只能包含 Dijit 组件,也就是必须继承自 dijit._Widget
。不能包含普通的 DOM 节点。对于 DOM 节点,可以用一个 dijit.layout.ContentPane
封装之后,再添加到 dijit._Container
中。dijit._Container
的子组件的 DOM 节点都是属性 containerNode
所表示的 DOM 节点的子节点。而 containerNode
的值与 domNode
不一定相同。只有 containerNode
中包含的子组件才会在 destroyDescendants()
方法中被销毁。一般来说,在 Dijit 组件的 domNode
下指定一个 DOM 节点作为 containerNode
。dijit._Container
负责管理其中包含的子组件,其 startup()
方法会负责调用子组件的 startup()
方法。对于通过 addChild()
方法动态添加的子组件,如果子组件的 startup()
方法没有被调用过,则会调用此 startup()
方法。removeChild()
只是将子组件移除,使其不再受 dijit._Container
的管理,并不会销毁该子组件。
在介绍完 dijit._Container
之后,下面介绍如何对 Dijit 组件进行管理。
Dojo 会负责维护当前页面上所有 Dijit 组件的一个注册表,里面包含了所有的 Dijit 组件对象。该注册表可以通过 dijit.registry
来访问,它是一个 dijit.WidgetSet
类的实例。dijit.WidgetSet
实际上是一个 Dijit 组件的 ID 及其对象对应的查找表。通过组件的 ID 就可以查询到组件对象。dijit.WidgetSet
所包含的方法用来对此查找表进行操作。这些方法包括:
add(widget)
用来添加新组件 widget
;remove(id)
用来根据 ID 移除组件。byId(id)
用来通过 ID 查找组件;byClass(cls)
用来根据类名来查找组件,如 dijit.registry.byClass("dijit.form.Button")
用来查找页面上所有的 dijit.form.Button
组件。该方法的返回值是一个新的 dijit.WidgetSet
对象。toArray()
返回一个包含所有组件对象的数组。forEach()
、filter()
、map()
、every()
和 some()
:这些方法的含义与用法与 Dojo 基本库中处理数组的同名方法的含义与用法是相同的,都是用来对所包含的组件对象进行处理。
除了全局的组件注册表 dijit.registry
之外,Dijit 库还提供了其它的方法。这些方法包括:
dijit.byId(id)
用来根据 ID 在页面上查找组件。dijit.getUniqueId(widgetType)
用来为指定组件类别 widgetType
中的新组件生成惟一的 ID。dijit.findWidgets(root)
用来查找指定 DOM 节点 root
中所包含的 Dijit 组件。但是不包括嵌套的 Dijit 组件。dijit.getEnclosingWidget(node)
用来查找包含 DOM 节点 node
的 Dijit 组件。
在管理 Dijit 组件的时候,有下面几个问题需要注意:
dijit.WidgetSet
对象。这样就可以利用 dijit.WidgetSet
所提供的管理功能。dijit.registry
是通过组件的 ID 来进行查找的,因此要求 ID 是全局惟一的。对于系统生成的 ID,是可以保证其惟一性的。不过开发人员也可以为组件提供自己的 ID,这个时候就需要格外注意 ID 的惟一性。如果试图创建一个 ID 为 myId
的组件,但是页面上已经存在 ID 相同的组件,Dojo 会抛出一个异常 "Tried to register widget with id==myId but that id is already registered"
。造成这种情况的原因比较多:第一种可能是由于编程失误造成了 ID 重复,这种情况下只需要修改重复的 ID 即可;另外的可能是准备复用某个 ID,但是前一个 Dijit 组件的销毁不彻底,并没有从全局组件注册表 dijit.registry
中移除掉自己。当再次使用此 ID 创建组件的时候就出现了错误。在 dijit._Widget
类的 destroy()
方法中包含了从 dijit.registry
中删除当前组件的实现。如果自己开发的组件覆写了 destroy()
方法,而没有通过 this.herited(arguments)
来调用父类的逻辑的话,就很容易出现这样的错误。
在介绍完 Dijit 组件管理之后,下面介绍实例化 Dijit 组件的两种方式。
一般来说,实例化 Dijit 组件有两种方式:声明式和编程式。声明式的方式指的是在 HTML 代码中以描述的方式来定义 Dijit 组件,由 Dojo 在运行时刻把这些声明的组件实例化。编程式的方式是开发人员在代码中显式的通过 new
操作符来实例化某个 Dijit 组件。实例化一个 Dijit 组件需要两个参数,第一个是混入到组件实例中的包含配置属性的 JavaScript 对象,第二个则是组件所使用的 DOM 节点。这两种方式的不同之处在于如何提供这两个参数的值。下面首先介绍声明式的方式。
使用声明式的时候,需要在 DOM 节点上添加属性 dojoType
,其值是 Dijit 组件类的全名。这样就声明了在运行时刻会从此 DOM 节点上创建一个新的 Dijit 组件。如 <div dojoType="dijit.form.Button" />
声明了会从此 div
元素上创建一个 dijit.form.Button
组件。而对于混入到组件实例中的属性,则是通过此 DOM 节点上的属性值来声明的。由于在 HTML 代码中声明属性的时候只能使用字符串,而 Dijit 组件中的属性是有数据类型的,因此需要一个转换的过程。了解此过程有助解决一些属性无法设置的问题。这个转换过程具体如下:
dojoType
声明的组件类,遍历该类的 prototype
对象中的属性,去掉以“_”开头的和 Object.prototype
中包含的属性,其余的就是可以在声明 Dijit 组件的时候使用的属性。这些属性的值的数据类型也会被记录下来。
dojo.declare("myWidget", dijit._Widget, { count : 1, valid : false, names : ["Alex", "Bob"] }); <div dojoType="myWidget" count="20" names="John, Jason" /> |
在 代码清单 2 给出的例子中,myWidget
中定义了 3 个属性:count
、valid
和 names
,其数据类型分别是数字、布尔型和数组。在声明 Dijit 组件的时候,在 DOM 节点上添加了属性 count
和 names
。属性 count
的值被转换成数字,而属性 names
的值被转换成数组。
除了通过 DOM 节点的属性来设置 Dijit 组件的属性之外,还可以通过 <script>
子元素来声明方法。<script>
元素的内容就是方法体本身。支持的声明方式有三种:
<script type="dojo/method" event="myHandler">
:声明的 JavaScript 方法与其它简单属性一样,被混入到组件对象中。属性名称是 event
的值。<script type="dojo/method" >
:声明的 JavaScript 方法在组件实例化之后会被立即执行。<script type="dojo/connect" event="onClick" >
:声明的 JavaScript 方法在组件实例化之后会通过 dojo.connect()
绑定到 event
所指明的事件上。<div dojoType="myWidget" myHandler="alert('Hello World!');" />
。不过 <script>
元素提供了更多的灵活性,比如可以通过属性 args
来声明参数,属性 with
来使用 JavaScript 中的 with
表达式。在 <script>
元素内部编写方法体也更加清晰,可以使用代码缩进。代码清单 3 给出了一个使用 <script type="dojo/method" >
的示例。
<div dojoType="emailDisplayer" jsId="myEmailDisplayer"> <script type="dojo/method" event="setEmailByName" args="name"> var email = name + "@example.org"; this.attr("email", email); </script> </div> |
代码清单 3 中使用了 代码清单 1 中给出的显示电子邮件地址的 Dijit 组件,并通过 <script type="dojo/method" >
定义了一个新的 JavaScript 方法 setEmailByName
。通过属性 jsId
可以为组件设置一个全局的引用名称。当组件实例化之后,就可以通过 myEmailDisplayer.setEmailByName("Alex")
来调用方法 setEmailByName()
,组件会显示出 Alex@example.org
。
在声明了 Dijit 组件之后,需要通过 dojo.parser.parse(rootNode, args)
方法来完成组件的实例化工作。该方法可以遍历 rootNode
的子孙节点,根据是否包含属性 dojoType
来判断是否为 Dijit 组件。如果是的话,就实例化该组件。该方法会返回一个实例化出来的组件列表。在实例化一个 Dijit 组件的时候,默认的方式是通过 new
操作符来完成的。dojo.parser.parse()
方法也允许开发人员自定义组件实例化的行为。通过在组件类或是其 prototype
对象上定义 markupFactory
方法就可以完成。dojo.parser.parse()
方法会优先检查是否存在 markupFactory
方法。如果有的话,就把此方法的返回值作为实例化出来的组件对象。
与声明式的方式相比,编程式的方式相对简单。只需要通过 new
操作符,并传入合适的参数即可。如 new dijit.form.Button({label : "Press Me!"})
就创建了一个新的 dijit.form.Button
组件。
声明式和编程式两种方式是密切相关的。只不过使用声明式的情况下,是由 Dojo 库在后台以编程的方式来实现 Dijit 组件的实例化的。两种方式从使用上来说,声明式方式比较易懂,开发人员不需要了解太多 JavaScript 语言的细节,就可以用直观的方式来定义出所需要创建的组件;编程式的方式则功能更加强大,给了开发人员更多的灵活性。如果创建组件时所需要的参数是在运行时刻动态计算出来的话,使用声明式就无法实现,只能以编程的方式来创建。
一般来说,对于简单的和容器类的组件,最好使用声明式的方式来创建。简单的组件用声明式的方式非常简洁;而容器类的组件,即混入了 dijit._Container
的组件,如 dijit.layout.TabContainer
和 dijit.layout.BorderContainer
,使用声明式的方式可以很直观的定义容器的子组件,而使用编程式的方式则需要通过 addChild()
来逐个添加子组件,过程比较繁琐。如果创建组件时可以允许的属性比较复杂,或是属性的值需要动态计算,则最好使用编程式的方式来创建。开发人员可以根据实际情况来选择最适合自己的组件创建方式。
Dojo 默认提供的 Dijit 组件库中包含的都是一些通用的组件。在 Ajax 应用开发中,经常会需要根据业务逻辑的需要开发出自己的组件。在开发自己组件的时候,深入了解 Dijit 组件的编程模型和相关的最佳实践是大有益处的。本文介绍了 Dijit 组件编程模型中的核心类 dijit._Widget
、dijit._Templated
和 dijit._Container
,以及管理和实例化 Dijit 组件相关的内容。在介绍的过程中,穿插了对最佳实践的说明,可以帮助开发人员更好的开发自己的 Dijit 组件。
本人所发表的内容仅为个人观点,不代表 IBM 公司立场、战略和观点。
学习
讨论
联系客服