Chinaunix首页 | 论坛 | 博客
  • 博客访问: 385779
  • 博文数量: 69
  • 博客积分: 1984
  • 博客等级: 上尉
  • 技术积分: 953
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-28 00:43
个人简介

学无所长,一事无成

文章分类

全部博文(69)

文章存档

2015年(19)

2014年(14)

2013年(9)

2012年(17)

2010年(10)

我的朋友

分类: JavaScript

2014-06-26 16:55:47

原文:http://dojotoolkit.org/documentation/tutorials/1.10/templated/
难度等级:中级  Dojo 版本:1.10

起步

如果你不了解用 Dijit 创建小部件 (widgets)的基础知识,请先学习:Understanding _WidgetBase 。这两篇文章: Creating a custom widget tutorial 和  也可以帮助你学习如何创建小部件(widgets)。

Dijit 的 _WidgetBase 为创建 widgets 打下一个良好的基础,但 Dijit 中真正神奇的是 _TemplatedMixin 混入。利用 _TemplatedMixin 和_WidgetsInTemplateMixin,你可以快速创建易维护,易修改,易操作的 widgets。

_TemplatedMixin 的基本概念十分简单:开发人员创建一个小型的 HTML 文件,做少量扩展,然后在运行时将 HTML 文件以字符串形式载入(或者在 build 阶段进行嵌入) ,载入后此模板派生出的实例就可以重用这个 HTML 了。

让我们看看 _TemplatedMixin 定义了些什么 (以及为何这样做),然后用它创建一个简单的 widget。

注: _TemplatedMixin 一般用于混入(mixin),不要直接继承。在基于类的语境中,这意味着他更像一个接口而非类 (尽管在 JavaScript 中两者间的差异很模糊).。请参考 Dojo Declare Tutorial 了解 Dojo 中类的工作原理。

 _TemplatedMixin 提供了什么

将_TemplatedMixin 混入到  widget 的定义中,会添加如下一个属性:

  1. templateString // a string representing the HTML of the template


这个属性简单的令人发指 — 这么一个简单的东西能有那么大威力? 答案就要追询 _TemplatedMixin 往你的 widget 中添加了什么。

小提示: 还添加了一个 templatePath 属性,但模板载入时已经不需要用这个了。出于向后兼容考虑依然保留。后面我们会展示如何使用 dojo/text! 来载入一个 widget 的模板。

被重载的方法-Overridden Methods

除添加上面说的属性外, _TemplatedMixin 还重载了Dijit widget 架构中提供的的两个方法: buildRendering 和 destroyRendering。这两个方法用于解析并填充模板 (buildRendering) 和销毁  widget 的 DOM 元素 (destroyRendering)。

这两个方法极其重要,如果你要重载他,那一定要调用 this.inherited(arguments) 来保证父类的方法被正确调用。参考 Understanding _WidgetBase 一文,了解 widget 生命周期的概念。

使用 _TemplatedMixin

要让你的 widget "模板化",你只需在声明你的 widget 时将 dijit/_TemplatedMixin 作为第二个或更靠后的参数传入到父类列表中(译注:就是不要做第一个,否则会成为 prototype)。 举例来说,某个小部件可能如下声明:

  1. define([
  2.     "dojo/_base/declare",
  3.     "dijit/_WidgetBase",
  4.     "dijit/_TemplatedMixin",
  5.     "dojo/text!./templates/SomeWidget.html"
  6. ], function(declare, _WidgetBase, _TemplatedMixin, template) {
  7.  
  8.     return declare([_WidgetBase, _TemplatedMixin], {
  9.         templateString: template
  10.     });
  11.  
  12. });


Dijit 坚持一个标准,用单独的目录 templates 来存放 widget 模块— 我们也建议你遵循这个标准。

注意上面代码中的声明部分,我们使用了 templateString  属性,它会同  dojo/text!{path} 一起影响模板的加载。这是设定模板文件引用的推荐方式,因为他可以确保文件异步加载和正确的合并集成。

现在我们已经将 widget 声明成模板式的了,现在我们编写模板,声明 hooks。


编写模板

一个模板就是一个 HTML 文档片段,我们可以定义 DOM 结构,声明同 widget 绑定的 “hooks”。让我们深入学习这些 hooks,以及模板中的变量替换。我们构想某个widget 的模板如下:

  1. <div class="${baseClass}">
  2.     <div class="${baseClass}Title" data-dojo-attach-point="titleNode"
  3.             data-dojo-attach-event="onclick:_onClick"></div>
  4. </div>

例子很简单,但演示了 Dijit 模板体系最重要的三个要素:变量替换,attach points,和事件关联。

注意在你定义一个 template 时,它只能拥有一个 root 节点(就像 XML 一样)。最顶层是不允许有多个节点的。

变量替换

模板使用一种简单的变量占位语法,在 DOM 渲染时就可以进行变量替换。类似如下:

  1. ${property}

变量名就使用 widget 中定义的属性或字段;前面例子中使用了
baseClass 属性 (每个 widget 都会有这个属性),自定义的字段一样可以这样用 — 比如,我们在自己的小部件中定义了一个属性 foo ,模板中我们就可以用 ${foo} 进行引用。如果某个属性恰好是个对象,而我们需要引用这个对象的某个属性,那我们可以通过对象引用的点操作符进行:

  1. ${propertyObject.property}
To prevent _TemplatedMixin from escaping quotations within a string, place a "!" before the full variable name, like so:

  1. ${!property}

模板中,建议只针对小部件生命周期中固定不变的值进行变量替换。换言之,如果你要设置小部件的某些值,那就使用小部件的 set() 方法,不要用 postCreate 方法。

Attach Points

Dijit 的模板系统提供了一个特殊的属性叫 attach point—这个是采用 HTML5 的数据属性语法声明。attach point 主要作用就是当其声明的 DOM 元素创建时,在小部件中添加一个属性值,这个属性会引用我们创建的这个 DOM 元素。(意译,原文相当的绕) 我们看上面那个例子程序,这个小部件的模板定义了两个 DOM 元素。 主元素(外层的 div )可以通过 domNode 引用,内层的元素可以通过 titleNode 引用。

通常模板的 root 节点会作为自定义小部件的 domNode 属性,因此你一般不需要定义一个 attach point。 但有时我们需要同其他系统模块协作时需要这样干,比如 Dijit 的焦点管理。

The containerNode Attach Point

Dijit 还定义了一个 "神奇的" attach point 叫做 containerNode。其基本概念就是提供一个容器,当你采用声明式语法创建小部件时,额外的 标签就可以丢到这里面来。例子,下面是 SomeWidget 的模板:

  1. <div class="${baseClass}">
  2.     <div class="${baseClass}Title" data-dojo-attach-point="titleNode"
  3.             data-dojo-attach-event="ondijitclick:_onClick"></div>
  4.     
  5.     <div class="${baseClass}Container"
  6.             data-dojo-attach-point="containerNode"></div>
  7. </div>
采用声明式语法创建这个小部件:(译注:div 内部的附加内容就会放入 containerNode 中)

  1. <div data-dojo-type="demo/SomeWidget"
  2.         data-dojo-props="title: 'Our Some Widget'">
  3.     <p>This is arbitrary content!</p>
  4.     <p>More arbitrary content!</p>
  5. </div>
当 Dojo parser 遍历文档时,他会找到我们的 widget 然后将其实例化— 实例化过程中,他会将 widget 内部的标签追加到 containerNode内部。最后 widget 完成 startup 后,最终的 DOM 结果如下:

  1. <div id="demo_SomeWidget_0" class="someWidgetBase">
  2.     <div class="someWidgetTitle">Our Some Widget</div>
  3.     <div class="someWidgetContainer">
  4.         <p>This is arbitrary content!>
  5.         <p>More arbitrary content!>
  6.     </div>
  7. </div>

我们简化了一些属性;真实世界 Dijit 渲染模板时不会删除任何东西。

如果我们在标签内部嵌入了其他的 widget,而且你定义的 widget 包含 containerNode ,那么这个 widget 可以在你定义的 widget 的容器中正确创建。举例如下:

  1. <div data-dojo-type="demo/SomeWidget">
  2.     <p>This is arbitrary content!</p>
  3.     <div data-dojo-type="dijit/form/Button">My Button</div>
  4.     <p>More arbitrary content!</p>
  5. </div>

事件绑定-Event Attachments

除了 attach points,Dijit 的模板系统还提供了一种手段,能够让你将 DOM 的原生事件关联到自定义 widget的方法上。这是通过 HTML5 的data 属性定义的(data-dojo-attach-event)。这个属性值是逗号分隔的键值对组成的字符串,键值对由冒号分隔;主键为DOM 的原生事件,值就是你的 widget 方法,两者关联当事件触发时调用方法。如果只关联了一个事件,可以忽略逗号分隔符。示例,下面是一个 Dijit's MenuBarItem 中的 dojo-data-attach-event 定义:

  1. data-dojo-attach-event="onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick"

当你的 widget 实例化完毕,DOM 片段也基于模板创建好,Dijit 模板系统开始遍历事件关联,然后"自动魔术般地"将 DOM 同 widget 进行事件关联(使用  dojo/on),界面效果同控制代码关联竟是难以置信的简单。另外事件触发时,DOM 原生事件接收的参数会原封不动的传递给你的 widget 方法,这样你就可以完全控制你的浏览器。

另外,我们也可以通过 dijit/_OnDijitClickMixin  添加一个改版的 ondijitclick 事件,他比 DOM 标准的 onclick 功能更多。为此,我们先修改 widget 声明如下:


  1. define([
  2.     "dojo/_base/declare",
  3.     "dijit/_WidgetBase",
  4.     "dijit/_OnDijitClickMixin",
  5.     "dijit/_TemplatedMixin",
  6.     "dojo/text!./templates/SomeWidget.html"
  7. ], function(declare, _WidgetBase, _OnDijitClickMixin, _TemplatedMixin,
  8.         template) {
  9.  
  10.     return declare([_WidgetBase, _OnDijitClickMixin, _TemplatedMixin], {
  11.         templateString: template
  12.         // any custom code goes here
  13.     });
  14.  
  15. });
然后修改 widget 模板如下:

  1. <div class="${baseClass}">
  2.     <div class="${baseClass}Title"
  3.         data-dojo-attach-point="titleNode"
  4.         data-dojo-attach-event="ondijitclick:_onClick"></div>
  5.     <div>And our container:</div>
  6.     <div class="${baseClass}Container"
  7.         data-dojo-attach-point="containerNode"></div>
  8. </div>

The _WidgetsInTemplateMixin Mixin

最后,Dijit 的模板系统还允许你使用_WidgetsInTemplateMixin 混入来创建更复杂的 widgets。这个 mixin 会告诉模板系统,你的模板中包含其他的 widgets ,因此在实例化你的 widget 时需要将他们一并实例化。

例子如下,我们修改声明,让其包含一个  Dijit button:


  1. define([
  2.     "dojo/_base/declare",
  3.     "dijit/_WidgetBase",
  4.     "dijit/_OnDijitClickMixin",
  5.     "dijit/_TemplatedMixin",
  6.     "dijit/_WidgetsInTemplateMixin",
  7.     "dijit/form/Button",
  8.     "dojo/text!./templates/SomeWidget.html"
  9. ], function(declare, _WidgetBase, _OnDijitClickMixin, _TemplatedMixin,
  10.             _WidgetsInTemplateMixin, Button, template) {
  11.  
  12.     return declare("example.SomeWidget", [_WidgetBase, _OnDijitClickMixin,
  13.         _TemplatedMixin, _WidgetsInTemplateMixin
  14.     ], {
  15.         templateString: template
  16.         // your custom code goes here
  17.     });
  18.  
  19. });
然后创建模板如下:

  1. <div class="${baseClass}" data-dojo-attach-point="focusNode"
  2.         data-dojo-attach-event="ondijitclick:_onClick"
  3.         role="menuitem" tabIndex="-1">
  4.     <div data-dojo-type="dijit/form/Button"
  5.         data-dojo-attach-point="buttonWidget">
  6.         My Button
  7.     </div>
  8.     <span data-dojo-attach-point="containerNode"></span>
  9. </div>

注意我们修改的模板,我们在 button 标签中添加了一个 attach point 叫 buttonWidget。这是 Dijit's attach point系统带来的附加好处,因为本质上是定义一个 widget,所以我们添加的属性 myWidget.buttonWidget  会指向一个实际的 button widget,而不仅仅是 DOM 元素。 这允许你创建一个“专业级-widgets”,比如一个浏览邮件列表的复杂  widget,还可以带上工具条等一大堆插件。

同时,请注意你需要将模板中用到的任何 widgets 都 require 进 module 中。widget 模板中我们没法利用 Dojo1.8 版本以后的dojo/parser 都具有的 "auto-require" 特性了,因为widget 创建时的生命周期管理都是基于同步模式,而 auto-require 特新需要采用异步模式管理。

除非你的模板文件确实需要,否则不要混入  dijit/_WidgetsInTemplateMixin。因为混入的东西可能会影响 widget 性能,如果大量使用,甚至影响应用性能。

小结

本章中,我们学习了基于 _TemplatedMixin 和_WidgetsInTemplateMixin 混入的 Dijit 强大的模板系统,利用他可以快速创建自定义 widgets。我们学习了模板系统的 attach points 和 event 关联,我们可以将 DOM 元素绑定到代码上,还学习了在模板中如何进行变量替换,还学习了在自己的 widgets 中如何包含其他 widgets以创建"专业级-widgets"。

Happy widget building!



阅读(2479) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~