创建基于模板的微件

创建基于模板的微件

Creating Template-based Widgets

In this tutorial, you'll learn about the importance of Dijit's _TemplatedMixin mixin, and how to use templates to quickly create your own custom widgets.

本教程中,你将会了解Dijit中 _TemplatedMixin mixin的重要性,以及如何基于模板快速创建自定义微件。

Getting Started

开始

If you are not already familiar with the basics of creating widgets with Dijit you will want to first read the Understanding _WidgetBase tutorial. The Creating a custom widget tutorial and Writing Your Own Widget guide will also help you learn to create widgets.

如果你现在还不熟悉使用Dijit创建微件基础知识,你可能需要先阅读 理解_WidgetBase教程。创建自定义微件教程 和 创建自己的微件指南 也是很好的教程。

Dijit's _WidgetBase provides a fantastic foundation for creating widgets, but the _TemplatedMixin mixin is where Dijit really shines. With _TemplatedMixin and _WidgetsInTemplateMixin, you can quickly create widgets that are highly maintainable, quickly modifiable and easy to manipulate.

Dijit的_WidgetBase 为创建微件提供了一个很好的基础,不过_TemplatedMixin mixin 才是精华。有了_TmeplatedMixin 和 _WidgetsInTemplatedMixin,就可以快速的创建高可维护、可快速修改、易操作的微件。

The basic concept of _TemplatedMixin is simple enough: it allows a developer to create a small HTML file that has a few small extensions, and loads this HTML file as a string at run-time (or inlined during the build process) for re-use by all instances of the templated widget.

_TemplatedMixin 的基础概念足够简单:它允许开发人员创建一个小的带有扩展语法的Html文件,在运行时加载该HTML文件(也可以在构建过程中直接嵌入),被所有的实例使用。

Let's walk through what _TemplatedMixin defines (and why), and then build a simple widget from scratch using its functionality.

我们来看看_TemplatedMixin 定义了什么(以及为什么这样),之后构建一个简单的微件来测试这些功能。

Note that _TemplatedMixin is intended to be used as a mixin, and not directly inherited from. In class-based parlance, that means that is more like an interface than a class (although with JavaScript, the difference between the two is muddied). See the Dojo Declare Tutorial for more information on how classes work in Dojo.

注意_TemplatedMixin 一般用来作为继承混合器,而不是不会直接派生。从类的角度来说,它更像是接口而非类(尽管在JavaScript中,类和接口的区别有些模糊)。查看 DOJO 定义教程 可以获取更多Dojo中类使用的信息。

What _TemplatedMixin Provides

_TemplatedMixin 提供了什么

For the working developer, mixing _TemplatedMixin into a widget definition provides you with the following additional properties on your widget:

对于开发人员,将_TemplatedMixin 作为微件的接口类,能为微件增加以下属性:

templateString        //    a string representing the HTML of the template表示模板HTML的字符串

This property is deceptively simple — after all, how can so much power come from so little? The answer lies in what else _TemplatedMixin adds to your widget's definition.

这个属性很简单-怎能有这么多的功能来自于如此简单的属性?答案在于_TemplatedMixin 为微件增加的其他内容。

A small note: templatePath is also added, but no longer used for template loading. It is still there for backwards-compatibility. We'll show you later on how to use dojo/text! to load a widget's template.

小提示:_TemplatedMixin也为微件添加了templatePath ,但这个属性不在用于模板加载。这个属性依然存在,用来提供向后兼容性。下面我们会介绍如何使用dojo/text! 来加载一个微件的模板。

Overridden Methods
重写方法

In addition to the property above, _TemplatedMixin overrides two methods defined in Dijit's widget architecture: buildRendering and destroyRendering. These two methods handle the parsing and filling out of the template (buildRendering) and destroying the widget's DOM correctly (destroyRendering).

除了上面列出的属性,_TemplatedMixin 还重写了定义在微件中的两个方法:buildRendering 和destroyRendering。这两个方法用来处理模板的解析及填充(buildRendering)以及微件Dom节点的正确析构(destroyRendering)。

Because both methods are critical to the templating process, if you override either of these methods in your custom code — make sure that you include a call to the parent version by adding this.inherited(arguments) in your overridden method. See the Understanding _WidgetBase Tutorial for more information on the widget lifecycle.

因为这两个方法是模板的关键过程,如果你重写了这两个方法中的任意一个-记得要通过this.inherited(arguments)调用父类的方法。查看 理解_WidgetBase 教程 获取更多微件生命周期的相关知识。

Using _TemplatedMixin
使用_TemplatedMixin

To make your custom widget "templatable", all you need to do is add dijit/_TemplatedMixin as the second or subsequent argument in the array of class declarations for your widget. For example, a SomeWidget widget might be declared like so:

为了让自定义微件模板化,你需要做的只是把dijit/_TemplatedMixin作为微件类继承基类列表中的第二个或后续的参数即可。例如,SomeWidget 微件可能是这样定义的:

define([
    "dojo/_base/declare",
    "dijit/_WidgetBase",
    "dijit/_TemplatedMixin",
    "dojo/text!./templates/SomeWidget.html"
], function(declare, _WidgetBase, _TemplatedMixin, template) {

    return declare([_WidgetBase, _TemplatedMixin], {
        templateString: template
    });

});

Dijit adheres to a standard of creating a separate directory called templates in the folder containing the widget module — a standard we'd advise you follow in your own code.

Dijit 遵循一个标准,在微件的模块目录中创建一个单独的名为templates的目录存放微件的模板-我们建议你在编写自己的微件时也遵循这个标准。

Notice that in our bare-bones declaration above, we used the templateString property in conjunction with a template loaded via dojo/text!{path}. This is the recommended way of setting up references to your template files, as it ensures that the files can be loaded asynchronously and properly integrated when creating a build of the Dojo Toolkit.

Now that we've set up our widget declaration to be template-based, let's write a template and talk about some of the special hooks in them that are available.

注意在上面我们的最简单的定义中,我们使用了templateString 属性,通过dojo/text!{path}加载模板。这是设置模板文件的推荐方式,这种方式保证在构建时,文件能够异步加载并且正确集成。现在我们的微件定义已经是基于模板的了,我们再编写一个模板并讨论一下其中的特殊点。

Writing Templates

编写模板

A template is an HTML document fragment in which you define a DOM structure, along with any special "hooks" to tie things back into your widget declaration. Let's look at a quick example before diving into each of these hooks, and how variable substitution takes place in a template. Here's a hypothetical template for our SomeWidget, above:

模板就是一个HTML文件片段,让你可以定一个Dom结构,以及一些特殊的钩子与微件中的成员绑定。在深入了解这些钩子和变量替换之前我们先来看一个简单的例子,下面是SomeWiget的模板:

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

While simple, this template demonstrates three of the most important aspects of the Dijit template system: variable substitution, attach points, and event attachments.

尽管很简单,这个模板已经展示了Dijit模板体系的最重要的三个概念:变量替换、坐标点,事件绑定。

Note that when you define a template, it can only have one root node definition ( just like with XML documents). Multiple nodes at the top level is not allowed.

注意在定义模板时,模板只能有一个根节点(就像XML文件那样)。多个根节点是不允许的。

Variable Substitution
变量替换

A template can have values set on DOM rendering though the use of a simple variable placeholder syntax, which looks like this:

模板可以通过占位符使得值 Dom节点渲染时注入,使用的语法像下面这样:

${property}

The variable name is any property or field defined in your widget declaration; the example above used the propertybaseClass (available with any widget), but custom fields work just as fine — for instance, if we'd defined a property called foo in our SomeWidget, we would simply use ${foo} in our template. If the property in question happens to be a reference to an object, and you want to use the value of a property in that object, you may easily do so via normal object reference notation:

变量名可以是任意在微件中定义的属性或字段;上面的例子用的是baseClass属性(任何微件都包含该属性),自定义字段也是可以的-例如,如果我们在SomeWidget中定义了一个foo属性,我们就可以在模板中使用${foo}。如果属性是一个Object对象,而我们要使用该属性中的某个值,可以通过下面的方式应用:

${propertyObject.property}

To prevent _TemplatedMixin from escaping quotations within a string, place a "!" before the full variable name, like so:

为了避免_TemplatedMixin 去掉字符串中的引号,可以在变量之前加一个“!”,如下:

    ${!property}

Variable substitution in a template is only recommended for values that will not be changed during the lifetime of the widget. In other words, if you expect to be able to set the value of a property in a widget during the lifetime of your application programmatically, we recommend instead using your widget's postCreate method to set any variables programmatically through your widget's set() method.

在模板中进行变量替换建议只使用那些在微件的生命周期中不变的值。也就是说,当你想以编程方式在微件的生命周期中设置变量的值时,建议通过微件的set()方法而非微件的postCreate方法。

Attach Points
坐标点

Dijit's template system has a special attribute it will look for in your templates called an attach point — implemented using HTML5's data attribute syntax. An attach point tells the template renderer that when a DOM element is created with a data-dojo-attach-point attribute defined, to set the value of that attribute as a property of your widget to be a reference to the DOM element created. For example, the template for SomeWidget (above) defines two DOM elements. The main element (the outer div) can be referenced in your code through the property domNode, and the inner div element can be referenced in your code through the property titleNode.

Dijit的模板体系有一个被称为坐标点的属性,它会查找你的模板,通过html5的数据属性语法实现。当Dom元素带有data-dojo-attach-point 属性时,模板渲染器会将该属性作为微件的一个变量,并绑定到该Dom节点。。例如:SomeWidget的模板定义了两个Dom元素,主Dom元素(外层div)可以通过domNode访问,内层div可以通过titleNode属性访问。

Normally, the root node of your template becomes the domNode property of your widget, so you wouldn't normally include an attach point attribute in your definition. However, sometimes this is done in the template to allow the root node to also function with other subsystems, such as Dijit's focus manager.

正常情况下,根节点会跟微件中domNode属性关联,因此,不需要为根节点添加坐标点。不过,有时候也会添加,以使根节点在某些子系统中的表现像其他坐标点元素一样,例如Dijit的焦点管理器。

The containerNode Attach Point
containerNode坐标点

Dijit also defines a "magical" attach point called a containerNode. The basic concept of a container node is to provide some place for any additional markup to go if a widget is created declaratively. For example, given the template for SomeWidget:

Dijit 还定义了一个“魔力”的坐标点叫做containerNode(容器节点)。容器节点的基本功能是在以声明的方式创建微件时,提供一个能够添加其他标签的位置。例如,SomeWidget的模板如下:


<div class="${baseClass}">
    <div class="${baseClass}Title" data-dojo-attach-point="titleNode"
            data-dojo-attach-event="ondijitclick:_onClick"></div>
    <!-- And our container: -->
    <div class="${baseClass}Container"
            data-dojo-attach-point="containerNode"></div>
</div>

We might use it in declarative markup like so:

我们就能以下面的标签的方式使用该微件:

<div data-dojo-type="demo/SomeWidget"
        data-dojo-props="title: 'Our Some Widget'">
    <p>This is arbitrary content!</p>
    <p>More arbitrary content!</p>
</div>

When the Dojo parser traverses the document, it will find our example widget and instantiate it — and as part of that instantiation, any markup inside the widget will be appended to the containerNode. So when the widget is finished with its startup, the resulting DOM will look like this:

Dojo 解析器解析文档时,就会发现我们的样例微件,并实例化-作为实例化的一部分,所有微件中的标签都将添加到containerNode。因此,当微件调用startup之后,Dom元素会像下面这样:

<div id="demo_SomeWidget_0" class="someWidgetBase">
    <div class="someWidgetTitle">Our Some Widget</div>
    <div class="someWidgetContainer">
        <p>This is arbitrary content!</p>
        <p>More arbitrary content!</p>
    </div>
</div>

Note that we removed some of the custom attributes for brevity; Dijit does not remove them when rendering templates.

Also be aware that if you embed other widget definitions in the main markup, and your widget has a containerNode attach point, any widgets will be instantiated inside the container node. For example, the following is a typical scenario when assembling an application:

注意为了简洁,我们删除了部分自定义属性;在渲染模板时,dijit其实不会移除它们。另外需要注意的是,如果你在主微件中添加了其他的微件,而主微件也有一个containerNode坐标点的话,这些微件也将会在容器节点内部实例化。例如,下面是一个应用程序的典型场景:

<div data-dojo-type="demo/SomeWidget">
    <p>This is arbitrary content!</p>
    <div data-dojo-type="dijit/form/Button">My Button</div>
    <p>More arbitrary content!</p>
</div>
Event Attachments
事件绑定

In addition to attach points, the Dijit template system gives you a way of attaching native DOM events to methods in your custom widget. It does this through the use of the HTML5 data attribute data-dojo-attach-event. This is a comma-delimited string of key/value pairs (separated by colon); the key is the native DOM event to attach a handler to, and the value is the name of your widget's method to execute when that event is fired. If only a single event needs to be handled, omit a trailing comma. For example, here's the dojo-data-attach-event attribute defined on Dijit's MenuBarItem:

除了坐标点,Dijit的版本体系还允许在自定义微件中为本地Dom事件绑定方法。通过Html5的数据属性data-dojo-attach-event实现。形式是以逗号隔开的键值对;键是本地Dom事件,值是事件发生时要执行的微件中的方法名。如果只有一个事件要处理,去掉末尾的逗号。例如,下面是Dijit中MenuBarItem的例子:

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

When your widget is instantiated and the DOM fragment is created from your template, the Dijit template system will then go through any attached event definitions and "auto-magically" wire these events (using dojo/on) from the resulting DOM and your widget object — making it incredibly simple to wire your visual representation to your controlling code. In addition, when those event handlers are fired, the same arguments normally passed by the native DOM event mechanism will be passed along to your widget's handler so that you have full access to what the browser is reporting.

微件实例化模板中的Dom元素结构构件完成之后,Dijit模板体系会查找所有的事件绑定,并自动的将这些事件与微件对象关联(使用dojo/on)-这使得将显示的元素与控制代码绑定变得难以置信的简单。另外,当事件触发时,本地Dom事件的参数会传递到微件的响应函数,因此你可以完全掌握浏览器发出的事件内容。

Also, we want to use the dijit/_OnDijitClickMixin which adds in a modified event that supports more functionality than the standard DOM onclick event. Therefore we need to modify our widget declaration:

还有,我们希望使用dijit/_OnDijitClickMixin 事件,它增加了一个修改后的事件,比标准的Dom onclick事件支持更多的功能。因此我们将模板修改如下:

define([
    "dojo/_base/declare",
    "dijit/_WidgetBase",
    "dijit/_OnDijitClickMixin",
    "dijit/_TemplatedMixin",
    "dojo/text!./templates/SomeWidget.html"
], function(declare, _WidgetBase, _OnDijitClickMixin, _TemplatedMixin,
        template) {

    return declare([_WidgetBase, _OnDijitClickMixin, _TemplatedMixin], {
        templateString: template
        //    any custom code goes here
    });

});

We also need to modify our widget template:

我们还需要更改微件模板:

<div class="${baseClass}">
    <div class="${baseClass}Title"
        data-dojo-attach-point="titleNode"
        data-dojo-attach-event="ondijitclick:_onClick"></div>
    <div>And our container:</div>
    <div class="${baseClass}Container"
        data-dojo-attach-point="containerNode"></div>
</div>

View Demo

The _WidgetsInTemplateMixin Mixin

_WidgetsInTemplateMixin “接口”

Finally, Dijit's template system allows you to create more complex widgets from templates through the use of the_WidgetsInTemplateMixin mixin. This mixin tells the template system that your template has other widgets in it and to instantiate them when your widget is instantiated.

最后,Dijit的模板体系允许你通过_WidgetsInTemplateMixin接口来创建复杂的微件。这个接口告诉模板体系,你的模板中包含其他的微件,需要在微件实例化完成后实例化它们。

For example, let's modify both our declaration to always include a Dijit button:

例如,我们更改一下定义使其能包含一个Dijit按钮:

define([
    "dojo/_base/declare",
    "dijit/_WidgetBase",
    "dijit/_OnDijitClickMixin",
    "dijit/_TemplatedMixin",
    "dijit/_WidgetsInTemplateMixin",
    "dijit/form/Button",
    "dojo/text!./templates/SomeWidget.html"
], function(declare, _WidgetBase, _OnDijitClickMixin, _TemplatedMixin,
            _WidgetsInTemplateMixin, Button, template) {

    return declare("example.SomeWidget", [_WidgetBase, _OnDijitClickMixin,
        _TemplatedMixin, _WidgetsInTemplateMixin
    ], {
        templateString: template
        //    your custom code goes here
    });

});

And then we would create a template like:

然后我们将创建一个模板:

<div class="${baseClass}" data-dojo-attach-point="focusNode"
        data-dojo-attach-event="ondijitclick:_onClick"
        role="menuitem" tabIndex="-1">
    <div data-dojo-type="dijit/form/Button"
        data-dojo-attach-point="buttonWidget">
        My Button
    </div>
    <span data-dojo-attach-point="containerNode"></span>
</div>

Notice that in our modified template, we've added an attach point called buttonWidget along with the button's markup. This is an additional bonus of Dijit's attach point system; because the definition in question is to be a widget, the added property to our widget — myWidget.buttonWidget — will be a reference to the actual button widget, and not a reference to a DOM element. This allows you to create "uber-widgets" out of simpler building blocks, such as a widget to view a list of emails, a toolbar that has preset widgets in it, and a lot more.

注意在新的模板中,我们在button类型后面添加了一个名为buttonWidget的坐标点。这里有一个dijit的坐标点体系的另一个优点;因为我们定义的标签会生成一个微件,坐标点生成的属性-myWidget.buttonWidget-指代的是生成的button微件,而非Dom元素。这让你能够通过组合微件创建一个超级微件,例如浏览邮件列表的微件,包含预设微件的工具栏等等。

Also, notice that you should require in any widgets into the module that are used by the template. You cannot take advantage of the "auto-require" feature of the dojo/parser introduced in Dojo 1.8 with widget templates because the creation life-cycle is synchronous but the auto-require feature has to run asynchronously.

同时,注意你需要在微件中引入所有需要在模板中出现的微件引用。而不能依赖Dojo1.8微件模板体系引入的dojo/parser 的自动引入功能,因为创建微件的生命周期是同步的,而自动引入需要异步执行。

Unless you have an explicit need to define widgets in your templates, don't mixin dijit/_WidgetsInTemplateMixin. The extra overhead that it incurs can affect the performance of the widget, and your application, if overused.

除非你的模板中确实需要添加其他的微件,否则不要添加dijit/_WidgetsInTemplateMixin。 如果过度使用,它额外的开销会影响微件以及整个应用的性能。

Conclusion

结论

In this tutorial, we've learned about Dijit's powerful template system as implemented by the mixins _TemplatedMixin and _WidgetsInTemplateMixin, and how you can use this system to quickly create your own custom widgets for use in your applications. We've reviewed how the template system's attach points and event attachments allow you to quickly bind DOM elements to your code, and how to replace values in your template — as well as how to include other widgets in your widget template to create "uber-widgets".

在本教程中,我们见识了Dijit强大的模板系统,它通过以接口方式继承_TemplatedMixin and _WidgetsInTemplateMixin来实现,我们也学习了如何在系统中使用该体系快速创建自定义微件。我们复习了使用attach point绑定节点和使用事件绑定为节点添加事件,以及在模板中替换值-还有通过包含其他小微件来构建超级微件。

Happy widget building!

祝构建微件愉快!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值