AMD模块介绍(翻译)

http://dojotoolkit.org/documentation/tutorials/1.10/modules/index.html

Dojo支持以异步模型定义(AMD)方式编写的模块,让会让你的程序更加易读和易调试。在本教程中,我们会解释AMD的基础知识以及如何使用AMD。

如果你以前是使用1.7版本一下,想把代码迁移过来,这个教程是很有用的。本教程专注于介绍AMD。

概述

异步模块定义(AMD)模式是在dojo1.7的时候引入dojo的。对比之前的模块定义模式,新的模式包含了完整的异步操作、真正的可移植包、更好的管理模式、改良后的调试支持等。AMD是一种社区标准,这就意味着你写的模块也可以加载到其他库的ADM加载器中。在本教程中我们介绍AMD,以及如何使用它。

什么是模块?

一个模块是指可以用一个引用访问的值。如果你想在一个模块上加载多个数据或函数,那必须是在一个对象上以属性形式展现。如果我们只是定义一个简单的值,例如var tinyModule = 'simple value',AMD模块对此来说是多余的,但却是有效的。模块开始的作用是把你的代码分解成一个个小的逻辑块,以便能够处理特定的功能。如果你想定义一个人,包含姓名、地址等属性,并具有事件,以及一些函数,那么如果使用模块定义就变得很有意义。在文件系统中,一个模块都以一个独立的文件存储。

怎么创建一个模块

With AMD, you create a module by registering it with the loader.

A quick aside here — loader? What's a loader? The loader is the code (yes, it's just JavaScript!) that handles the logic behind defining and loading modules. When you load dojo.js or require.js, you get an AMD loader. The loader defines functions for interacting with it - require and define..

The global function define allows you to register a module with the loader. Let's look at a few examples:

使用AMD中的加载器注册的方式可以创建一个模块。

这里引出了一个概念,加载器。什么是加载器?加载器是一段代码(只是javascript代码),在定义和加载模型后,处理逻辑。当你加载dojo.js或者requires.js时,你就得到了AMD加载器。加载器定义了require和define函数。

全局函数define函数可以让你使用加载器注册一个模块。请看下面的例子。

 define(5);

这是一个最简单但却有效的例子,注册的值是5。

 define({
library: 'dojo',
version: 1.10
});

做点更有意思的,通过上面的代码,我们定义了一个包含了两个属性的模块。

 define(function(){
var privateValue = 0;
return {
increment: function(){
privateValue++;
}, decrement: function(){
privateValue--;
}, getValue: function(){
return privateValue;
}
};
});

在这个例子中,我们通过Define定义了一个函数。该函数包含的子函数及数据都被加载器以模块的形式存储起来。代码在定义的时候,使用了闭包,这样可以定义的私有变量就不能为外部的代码访问到。但可以被模块内部的函数作为模块的属性返回和设置。

如何加载模块

For starters, we need to understand how modules are identified. In order to load a module, you need some way of identifying it. Similar to the module/package systems of other programming languages, an AMD module is identified by its path and file name. Let's save the code from the above example in a folder:

首先我们要了解模块如何被识别的。为了加载模块,我们先要了解如何标识模块。类似于其他编程语言,AMD也是通过路径和文件名标识模块。例如下面的代码:

 app/counter.js

Let's also add a loader (Dojo of course!) and an index.html - the entry-point for our application. This gives us the following file structure:

我们还需要我们的dojo以及index.html,index.html是我们程序的入口点。文件结构如下:

 /
index.html
/dojo/
/app/
counter.js

index.html页面的代码如下:

 <html>
<body>
<script src="dojo/dojo.js" data-dojo-config="async: true"></script>
<script>
require([
"app/counter"
], function(counter){
log(counter.getValue());
counter.increment();
log(counter.getValue());
counter.decrement();
log(counter.getValue());
});
</script>
</body>
</html>

让我们回顾一下,我们刚才都做了什么?

  1. 在app/counter.js,我们调用了define的加载器注册了一个模块。请注意,我们定义的这个模块是一个对象的引用,不是一个构造函数-这就意味着模型的每个功能都引用于同一个对象。一般来说模块返回构造函数,但有些情况下,也可以返回单例对象。
  2. 在文件系统中,我们的自定义的模型存储在Index.html文件同级目录下的一个文件夹下。AMD加载器(dojo.dojo.js)位于所在文件夹位于Index.html页面的同级目录下。在加载模块的时候,我们没有进行任何额外的配置,就能够加载了app/counter.js模块,并得到其返回的值。
  3. 在index.html页面中,我们调用了require加载"app/counter"模块。你可以通过require(["app/counter"])加载模块。如果里面的代码引用了其他模块,你不必要引用所有的模块。如果你想引用一个模型,需要提供回调函数。加载函数会确保引用的模块被加载,并且作为参数传递给回调函数。就像其他函数一样,你可以随意命名你的参数-参数命名时和模块的名称没有一点关系。但在参数命名时和模块名称一致是一种好的编码方式。

模块加载模块

我们之前的例子都是使用的define函数的简单用法。当一个应用使用很好的模块组织架构的时候,自然的会有很多模块相互依赖。define函数会自动的加载你的模块依赖的其他模块。在定义模块的值之前,就把该模块依赖的其他模块在define函数中罗列出来。

 define([
"dojo/_base/declare",
"dojo/dom",
"app/dateFormatter"
], function(declare, dom, dateFormatter){
return declare(null, {
showDate: function(id, date){
dom.byId(id).innerHTML = dateFormatter.format(date);
}
});
});

This example demonstrates some more typical features of AMD applications:

这个例子展示了更多的AMD应用特性。

  1. 多个依赖-dojo/dom和app/dateFormatter(假设我们定义了这个)都列入了依赖列表中。
  2. 返回了一个构造函数-为模块起一个适当的名字,例如app/DateManager。使用该模块的代码如下所示。
 require([
"app/DateManager"
], function(DateManager){
var dm = new DateManager();
dm.showDate('dateElementId', new Date());
});

在使用dojo开发之前,AMD是你必须熟悉的概念之一。declare是另外一个重要的函数,如果你还不熟悉dojo/_base/declare,下面可以看该教程。tutorial

使用插件

除了常规的模块之外,AMD加载器还会调用一个具有特殊特性的模块-插件。和加载普通模块相比,插件是用来扩展加载器新特性的。在模块后面加上特殊字符!,就可以标识该模块是作为插件请求的。!号后的数据直接传递给插件处理。通过一些例子我们可以看到这会让代码保持清洁。Dojo提供了几个默认的插件,分别是dojo/text, dojo/i18n, dojo/has and dojo/domReady,让我们看下这些插件怎么用。

dojo/Text

当需要从文件中加载字符串的时候,就会用到dojo/text。一旦调用一次,模块就会被缓存,这样会减少网络请求。html字符串加载就需要dojo/text模块。录入加载小部件的模板,请求模块的代码如下:

 // in "my/widget/NavBar.js"
define([
"dojo/_base/declare",
"dijit/_WidgetBase",
"dijit/_TemplatedMixin",
"dojo/text!./templates/NavBar.html"
], function(declare, _WidgetBase, _TemplatedMixin, template){
return declare([_WidgetBase, _TemplatedMixin], {
// template contains the content of the file "my/widget/templates/NavBar.html"
templateString: template
});
});

dojo/i18n

dojo/i18n loads language resource bundles according to the web browser's user locale. Its usage looks like this:

dojo/i18n会根据浏览器用户所在地区的不同加载不同的语言资源。用法如下:

 // in "my/widget/Dialog.js"
define([
"dojo/_base/declare",
"dijit/Dialog",
"dojo/i18n!./nls/common"
], function(declare, Dialog, i18n){
return declare(Dialog, {
title: i18n.dialogTitle
});
});

关于如何使用i18n的更多信息参考internationalization tutorial

dojo/has

Dojo’s loader includes an implementation of the has.js feature detection API; the dojo/has plugin leverages this functionality for requiring modules conditionally. Its usage looks like this:

dojo加载器包含了使用has.js检测特性的API。dojo/has的插件特性可以用来检测加载模块的一些前置条件。代码如下所示:

 // in "my/events.js"
define([
"dojo/dom",
"dojo/has!dom-addeventlistener?./events/w3c:./events/ie"
], function(dom, events){
// events is "my/events/w3c" if the "dom-addeventlistener" test was true, "my/events/ie" otherwise
events.addEvent(dom.byId("foo"), "click", function(){
console.log("Foo clicked!");
});
});

dojo/domReady

dojo/domReady is the replacement for dojo.ready. It is a module that simply doesn’t resolve until the DOM is ready

dojo/domReady是代替dojo.ready的模块,该模块是监测DOM是否加载好。例子代码如下:

 // in "my/app.js"
define(["dojo/dom", "dojo/domReady!"], function(dom){
// This function does not execute until the DOM is ready
dom.byId("someElement");
});

注意一点,我们在回调函数的参数中没有设置该模块对应的参数。这是因为其返回的值是无价值的-我们只是拿这个模块用来控制回调函数。一些不需要直接调用的模块或插件在请求的时候可以放在模块列表的最后面,这样在回调函数的参数列表中就不需要体现该模块了。

即使没有数据传递,参数模块也需要感叹号。没有感叹号,你只是加载激活了dojo/domReady模块而已,并没有使用到它的特性。

总结

The basic understanding of AMD provided in this tutorial will get you started with Dojo development, but you will soon find yourself running into more complicated scenarios. Read the Advanced AMD Usage tutorial to learn how to deal with:

本教程提供了你AMD的基本用法。但你会发现你会陷入更复杂的场景之中。你可以看下Advanced AMD UsageAMD高级使用教程,用于解决这些问题。

  • 配置加载器,可以让加载器加载本地不同路径下的包以及不同的服务。
  • 创建轻便的模块包。
  • 加载同一个模块或库的不同版本。
  • 加载非AMD代码。
上一篇:[platform]Device和Driver注册顺序


下一篇:Java基础知识强化之集合框架笔记27:ArrayList集合练习之去除ArrayList集合中的重复字符串元素