1、配置加载器
在整个文章里,我们假设应用的文件结构如下图所示:
/ index.html js/ lib/ dojo/ dijit/ dojox/ my/ util/
在使用AMD模块之前我们要做的第一件事就是配置加载器,使加载器在异步模式下运行。只要将async属性值改为ture就行:
1
|
<script data-dojo-config=
"async: true"
src=
"js/lib/dojo/dojo.js"
></script>
|
我们也可以在dojoConfig对象中设置async属性,但使用任意一种方法我们都得保证这个值在loader包含到网页之前设置。如果不这样,加载器就以兼容模式的同步模式运行。
在异步模式下,加载器只会定义两个全局函数:require用来加载模块;define用来定义模块。新的加载器和旧的加载器最鲜明的对比就是旧加载器会一股脑加载Dojo Base里的所有模块,而新的加载器就不会这样做。
接下来我们要做的就是给loader配置信息,这些信息里包含我们的模块地址:
1
2
3
4
5
6
7
8
9
10
|
var
dojoConfig = {
baseUrl:
"/js/"
,
tlmSiblingOfDojo:
false
,
packages: [
{ name:
"dojo"
, location:
"lib/dojo"
},
{ name:
"dijit"
, location:
"lib/dijit"
},
{ name:
"dojox"
, location:
"lib/dojox"
},
{ name:
"my"
, location:
"my"
, main:
"app"
}
]
};
|
在这个配置信息里,baseUrl设置包含所有我们JavaScript代码文件夹的地址,默认值为dojo.js所包含的那个文件夹;tlmSiblingofDojo属性被设置为false代表那些没有指定包、顶层模块的路径默认为baseUrl的地址。如果tlmSiblingofDojo默认值为true,若为true,那么认为他们和dojo包处于同一目录。这时,即使没有明确地定义until包,我们仍然调用until文件夹里的代码。
包就是模块的集合。packages包含三个主要的配置参数。name表示包的名称,实际值为包含模块的文件夹的名称;location表示包的位置,可以是一个相对于baseUrl路径或绝对路径;main是一个可选参数,表示要加载的模块,默认值为main.js,该属性可以重写,该示例中要加载的模块是app.js,该模块的确切位置是:/js/my/app.js。
2、引用模块
require函数包含下列参数:
(1)configuration:可选参数,值为对象,默认值为undefined。用来在加载器运行中修改配置
(2)dependencies:可选参数,值为数组,默认值为[],要生成模块的依赖项。
(2)callback:回调函数,你需要你的代码封装在一个回调函数,以支持异步加载和能够使用非全局引用模块。
示例一:
1
2
3
4
5
6
7
8
|
require(
[
"dojo/_base/declare"
,
"dijit/_WidgetBase"
,
"dijit/_TemplatedMixin"
],
function
(declare, _WidgetBase, _TemplatedMixin) {
// "declare" holds the dojo declare function
// "_WidgetBase" holds the dijit _WidgetBase constructor
// "_TemplatedMixin" holds the dijit _TemplatedMixin constructor
// Do whatever you want with these modules here.
});
|
require方法接受了一个模块标识符("dependencies")的数组,这个数组将作为它的第一参数,回调函数作为第二参数。数组里的依赖引用是有顺序的。一旦所有的依赖项准备好,它们会被按顺序传入回调函数作为函数的参数。回调函数是可选的,如果你只是想加载他们而并不想做些什么,你就可以忽略回调函数。
实例二:
1
2
3
4
5
6
7
|
require({
baseUrl:
"/js/"
,
packages: [
{ name:
"dojo"
, location:
"//ajax.googleapis.com/ajax/libs/dojo/1.9.2/"
},
{ name:
"my"
, location:
"my"
}
]
}, [
"my/app"
]);
|
在加载器运行中修改配置,它是通过将配置信息对象作为第一个参数传进去实现的。这样我们改变了配置信息,将dojo包指向了谷歌的CDN,不同于老版本模块机制,AMD机制支持隐式跨域加载,所以没有特殊的跨域版本是必要这样做的。
3、定义模块
define函数包含下列参数:
(1)moduleId:可选参数,表示模块签名,默认值为undefined,为了能够兼容旧版AMD语法,推荐不使用.
(2)dependencies:可选参数,值为数组,默认值为[],要生成模块的依赖项。
(3)factory:工厂函数,返回模块的值
1
2
3
4
|
// in "my/_TemplatedWidget.js"
define([
"dojo/_base/declare"
,
"dijit/_WidgetBase"
,
"dijit/_TemplatedMixin"
],
function
(declare, _WidgetBase, _TemplatedMixin){
return
declare([ _WidgetBase, _TemplatedMixin ], {});
});
|
注意,这里我们省略了第一个可选参数:模块签名。也可以这样:return declare("my._TemplatedWidget", [ _WidgetBase, _TemplatedMixin ], {}); 你可能会看到这样的代码,其实这样做事为了能够兼容旧版AMD语法。
在以上例子中,我们利用dojo.declare创建并返回了一份构造函数,当定义模块时一个重要的事就是工厂函数一旦被调用,加载器就会缓存它返回的值。从实践层面上来看,这就意味着模块可以依据相同的模块来轻松地共享对象。
采用旧版本Dojo编写的等效代码(不推荐使用):
1
2
3
4
|
dojo.provide(
"my._TemplatedWidget"
);
dojo.require(
"dijit._WidgetBase"
);
dojo.require(
"dijit._TemplatedMixin"
);
dojo.declare(
"my._TemplatedWidget"
, [ dijit._WidgetBase, dijit._TemplatedMixin ], {});
|
当定义模块时,值也可以作为对象:
1
2
3
4
5
|
// in "my/nls/common.js"
define({
greeting:
"Hello!"
,
howAreYou:
"How are you?"
});
|
备注:如果你在定义模块是没有回调函数,你将不可能引用任何的依赖项,所以这种定义方法是罕见的。
4、使用可移植模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
dojoConfig = {
packages: [
{ name:
"dojo16"
, location:
"lib/dojo16"
},
{ name:
"dijit16"
, location:
"lib/dijit16"
},
{ name:
"dojox16"
, location:
"lib/dojox16"
},
{ name:
"dojo"
, location:
"lib/dojo"
},
{ name:
"dijit"
, location:
"lib/dijit"
},
{ name:
"dojox"
, location:
"lib/dojox"
},
{ name:
"myOldApp"
, location:
"myOldApp"
},
{ name:
"my"
, location:
"my"
}
],
map: {
myOldApp: {
dojo:
"dojo16"
,
dijit:
"dijit16"
,
dojox:
"dojox16"
}
}
};
|
如果你的应用需要使用来至两个不同版本的Dojo,新的加载器能够轻松实现。使用map配置实现这种兼容。
5、编写可移植模块
为了使加载器能够执行可移植包,任何包内的模块引用都得使用relatie标识符。
1
2
3
4
5
6
7
8
|
// in "my/widget/NavBar.js"
define([
"dojo/dom"
,
"my/otherModule"
,
"my/widget/InfoBox"
],
function
(dom, otherModule, InfoBox){
// …
});
|
使用相对模块标识符代替绝对模块标识符:
1
2
3
4
5
6
7
8
|
// in "my/widget/NavBar.js"
define([
"dojo/dom"
,
"../otherModule"
,
"./InfoBox"
],
function
(dom, otherModule, InfoBox){
// …
});
|
相对于"my/widget/NavBar":
"dojo/dom"在一个独立包中,使用完整标示符
"my/otherModule"是在上一个目录中, 所以我们使用"../"
"my/widget/InfoBox"是在同一个目录中,所以我们使用"./"
参考文献:http://dojotoolkit.org/documentation/tutorials/1.9/modules_advanced/
http://dojotoolkit.org/documentation/tutorials/1.9/dojo_config/