DOJO AMD
Dojo 支持AMD规范中定义的模块定义,这使得更容易编写和调试代码。在本教程中,我们将讲解我们的基本理解以及AMD的使用。
概述
AMD(异步模块加载定义)规范是Dojo1.7版本开始采用的一种模块规范,相较于Dojo以前采用的模块风格,它在许多方面做了很大的改进和优化,比如完整的异步操作,真正的包可移植性,更好的依赖管理以及改进的debug支持。AMD是一个社区驱动的标准,这意味着,采用AMD规范编写的模块可以很容易地被其他AMD规范兼容的loader加载器或者库使用。在本教程中,我们将讲解AMD并展示给大家如何使用它。
什么是模块
module is a value that can be accessed by a single reference.
模块是一个可以通过单独的引用而被访问的值。如果你希望将一个模块中的很多数据和函数暴露给外界,那么它们就必须成为用一个对象来代表这个模块,然后将那些希望能被访问的内容作为这个对象的属性。从实际开发的角度来说,用这种方式可以为一个及其简单的值来定义模块 比如
var tinyModule= 'simple value'
这好像有点小题大做,但这是合法的。模块对于将你的代码模块化是很有意义的,你会将代码分解为一系列的逻辑子集来处理特定的功能。如果你希望用代码表示一个拥有姓名、地址等信息的人,并且这个人拥有一些方法,那么将这些代码独立出来,放到一个单独的区域是最好的。从文件系统的角度看,一个模块被保存为一个文件。
如何定义一个模块
在AMD中,我们通过给加载器注册模块的方式来定义它。
题外话:加载器?什么事加载器?加载器也是javascript代码,用于实现定义和加载模块的函数逻辑。当你载入 dojo.js 或者 require.js的时候,你就已经获得了一个AMD的加载器,这个加载器定义了与之进行交互的两个函数 “require” 和“define”。
这些全局函数定义允许你来注册一个模块到加载器里,如下面的例子
define(5);
这个例子相当简单,但这是合法的,这个模块的值就是一个数字。
define({ library:'dojo', version: 1.9 });
这个例子有一定的实际含义,当这个模块被加载后,我们可以得到一个拥有两个属性的对象。
define(function(){ varprivateValue = 0; return{ increment:function(){ privateValue++; }, decrement:function(){ privateValue--; }, getValue:function(){ returnprivateValue; } }; });
在这个例子中,我们将一个函数传递给了define,加载器会调用这个函数并且将他的结果保存为一个模块,这段代码采用闭包生成了一个不能被外部代码直接访问的私有数据,但是能通过一个对象的方法来进行检查和操作,这个对象最后作为模块的值而返回。
如何加载一个模块?
对于初学者,我们需要了解模块是如何被识别的。为了加载模块,你需要某些方式来标识它是一个可以被加载的模块。类似于其他编程语言的模块/包 系统,一个AMD模块是通过文件路径和文件名来标识的。下面就让我们把上面的例子保存到一个文件夹中。
app/counter.js
首先,我们要添加一个加载器(请参看Dojo教程)和index.html文件(我们程序的入口点)。我们的文件结构如下。
/
index.html
/dojo/
/app/
Counter.js
Index.html页面代码如下:
<html> <body> <scriptsrc="dojo/dojo.js"></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)的兄弟文件夹定位我们的模块,我们并不需要额外的配置来让加载器知道模块id“app/counter”就表示要加载app/counter.js这个文件并且将它的返回值作为模块.
3. 在我们的index.html中,我们调用require函数来加载”app/coounter”模块,我们可以简单地用require(["app/counter"])来加载模块。如果模块中的代码有类似于增加其他模块的边际效应,你就可能一点也不需要引用这个模块。但是,如果你需要引用这个模块,你就必须提供一个回调函数。加载器会确保模块被正确加载,而且一旦加载成功,就会调用你的毁掉函数将模块作为参数传递给它。像其他函数一样,你可以任意给参数命名,我们并没有强制参数名必须和模块名有关联。但是,采用和模块名类似的命名方式是一个比较好的实践方式。
模块加载其他模块
我们的例子只是展示了define 函数的简单用法。当我们的程序是由许多组织良好的模块组成的时候,这些模块之间必然存在许多的依赖关系。Define 函数可以自动为你的模块加载依赖模块。依赖关系列表参数是先于模块的值传递给define函数的。
define([ "dojo/dom", "app/dateFormatter" ],function(dom, dateFormatter){ returndeclare(null, { showDate:function(id, date){ dom.byId(id).innerHTML = dateFormatter.format(date); } }); });
这个例子展现了AMD程序的更典型的特点。
-
多个依赖模块-dojo/dom模块和假设的“app/dataFormatter”模块被声明在依赖关系列表参数中。
-
返回一个构造函数,这个模块的名字定义为 app/DateManger。调用这个模块的代码示例如下:
require([ "app/DateManager" ],function(DateManager){ vardm =newDateManager(); dm.showDate('dateElementId',newDate()); });
在开始应用Dojo开发之前,AMD是其中一个你需要首先熟悉的主题,除此之外,declare 也是另一个很重要的函数,如果你之前不熟悉dojo/_base/declare的话,就请下一步接着阅读 这篇文章。
使用插件
除了通常的模块之外,AMD加载器的另一个功能点就是一种新的被称为插件的模块。插件是用于扩展加载器的功能,使得它不再仅仅用于加载AMD模块,插件差不多像其他普通模块一样以同样的方式被加载,但是在模块标识符的后面会添加一个特殊的字符“!”来表明这是一个插件请求。“!”后面的数据会直接船体给插件进行处理,通过例子,我能会更清楚一些。Dojo默认是有一些插件的,其中有五个最重要的插件 dojo/text,dojo/i18n,dojo/has 和 dojo/domReady.下面我们就看看他们是如何使用的。
dojo/text
Dojo/text 是用于从文件(比如HTML 模板)中加载字符串, 这些字符串会被缓存起来,这样,后面再次调用加载同样的文件的时候 就不会再需要额外的网络请求了。在对web程序做build的时候,构建工具会将dojo/text加载的字符串直接替换到js代码中。比如,为一个模板widget导入模板,你需要这样定义你的模块。
// in "my/widget/NavBar.js" define([ "dojo/_base/declare", "dijit/_WidgetBase", "dijit/_TemplatedMixin", "dojo/text!./templates/NavBar.html" ],function(declare, _WidgetBase, _TemplatedMixin, template){ returndeclare([_WidgetBase, _TemplatedMixin], { // template contains the content of the file "my/widget/templates/NavBar.html" templateString: template }); });
dojo/i18n
Dojo/i18n会根据浏览器的用户区域设置而加载不同的语言资源包
// in "my/widget/Dialog.js" define([ "dojo/_base/declare", "dijit/Dialog", "dojo/i18n!./nls/common" ],function(declare, Dialog, i18n){ returndeclare(Dialog, { title: i18n.dialogTitle }); });
想要了解更多关于如何使用i18n的信息,请访问 国际化教程
dojo/has
Dojo/has Dojo的加载器包含了一套符合has.js定义的用于检测环境信息的API的实现代码,jojo/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 是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模块的返回值定义任何参数,这是因为它的返回值是没有用的。我们使用这个插件的目的只是延迟回调函数的执行。不需要使用返回值的那些模块或者插件应该添加在需要的依赖模块列表的尾部,这是因为这些模块和它们的局部变量的名称是按照顺序一一对应的。
尽管,数据没有被传递给domReady插件,但是“!”符号还是需要的。如果你不添加这个符号,那么你就仅仅是加载了dojo/domReady作为依赖模块,而不再起到这个插件本身的作用了。
结尾
本教程中对AMD基本介绍希望能有助于你开始Dojo开发工作,但是你将来还是会遇到更加复杂的场景,请阅读AMD使用进阶教程的学习如何处理:
- 配置加载器使得当加载器和包在不同路径甚至不同服务器的时候,加载器可以正常工作
- 创建可移植的模块包
- 加载不同版本的同一模块或者库。
- 加载非AMD代码
原文地址:
本文固定链接: http://www.huahuaxia.net/cs-research/internet/dojo_1-9_amd_module/ | 花花侠的IT世界