Dojo 工具包简介
Posted 05/07/2009 - 10:37 by daitao
Dojo 工具包简介
作者 SitePen, Inc. · 2008年12月12日
本文翻译自 Introducing The Dojo Toolkit
简述
Dojo 工具包包含了 Web 开发中的常用 JavaScript 工具。Base dojo.js
提供了绝大部分 web 开发都需要的 '必备' API,并提供秉承 "use at
will" 哲学的大量实用工具。Dojo 是完全免费的,有 AFL 和 new-BSD Open Source
License 两种 License 可选。
可以点击此处下载 Dojo,或在网页中通过<script>
标签引用:
<script type="text/javascript" charset="utf-8" src="http://ajax.googleapis.com/ajax/libs/dojo/1.2/dojo/dojo.xd.js"></script>
这就够了!上面的代码将从 Google Ajax API Content Distribution Network(使用 edge-caching 技术从最近的镜像中下载所需的库)载入 Dojo 工具包 (写本文时的版本是1.2 )。整个 Dojo 工具包都可以从 AOL CDN 和 Google 的新 Ajax API CDN 中获取--所有的新组件、新样式和图像。
点击此处可以查看所有 Dojo 组件概述,此处是 API 参考。Dojo 入门指南讲解了很多关键概念。DojoCampus 是一个很好的社区--提供了大量文档、教程和示例。docs.dojocampus.org 上有 Wiki ,以后将变成官方 Dojo 在线文档。
Dojo 库的格言是 "less Magic" -- 从0.9 版本起就使用了此格言。其 API 简洁、一致性强、有合适的命名空间并高度可扩展。每一个组件都是"随心所欲使用(use at will)";每一个特性都是可选的。
关于 Dojo:
- Dojo 是轻量级的 -- 压缩后只有26 KB ,使用高级选项可以只有6 KB。
- Dojo 的查询引擎支持所有 CSS3 选择器,设计包含前向查找 API 。
- Dojo 支持所有的主流浏览器:Opera 9+, FF2+, Safari 3+, 和 IE6+
- 尽管 Dijit ( Dojo 工具包UI组件) 可在 Opera 9 中运行,但 Opera 的快捷键特性使 Dijit 无法官方宣布支持,Dojo 的每次开发过程都会发布提高兼容性的补丁。
- Dojo 在全球有很多核心开发者。
- Dojo Build 和 Package 系统自动创建优化的 JavaScript "layers"、以及内联 CSS @import 和移除注释。
- Dojo 有 New BSD 或 AFL两种 License。
- DojoX 提供了大量 plugins, 而且这些插件有相似的 license 和支持,如客户端图表、Graphics API,高级 IO,大量 dojo.data Stores等。
- Dojo 不仅有很好的社区支持 (Dojo 网站,irc.freenode.net 中的 #dojo ,及 DojoCampus);Dojo 还有收费的商业支持,如 SitePen。Dojo也获得了很多主流互联网企业的支持。
Base 概述
在客户端,小小的 dojo.js
文件提供了大量功能。dojo.js
被称作 Base Dojo -- 为所有 web 开发者提供最稳定、最常用的功能。下面是 Base Dojo 的常见工具的简介(详细介绍需要非常长的文章):
dojo.addOnLoad
注册页面载入后应运行哪些函数。这其中应该包含 Dojo package 系统载入的工具包的其他组件。dojo.addOnLoad
也接收函数作为参数,如:
dojo.addOnLoad(function() {
console.log("The Page is ready!")
});
这是使用 DOM 的第一步。注意使用 Dojo 时不应该直接添加 onLoad 事件处理器(大部分库都不允许)。
dojo.require
载入 Dojo 模块或组件。如下面的代码载入高级动画插件和 easing 插件:
dojo.require("dojo.fx");
dojo.require("dojo.fx.easing");
dojo.addOnLoad(function() {
console.log("The Page 和 all Dojo dependencies are ready!")
});
不但将载入所指明的模块,系统还将载入指明模块所依赖的所有模块。所有依赖性被解析后将调用 dojo.addOnLoad
。
还有很多有用的 package 工具:dojo.requireIf
(条件载入), dojo.provide
(通知 package 系统已提供 module ,但不重新载入)。
组合使用 dojo.require
和 dojo.addOnLoad
可实现资源 lazy-load 。只需在你的网页中引入 base dojo.js
并在 addOnLoad
中调用 dojo.require()
:
// with just dojo.js, this is basically document.ready:
dojo.addOnLoad(function() {
// page is rendered, add extra code:
dojo.require("dijit.Dialog");
dojo.addOnLoad(function() {
// Dialog and all (if any) dependencies solved:
var thinger = new dijit.Dialog( {
title:"A Modal Dialog",
href:"remote.html"
});
thinger.startup();
// show it:
thinger.show();
});
});
上面例子中我们引入了 dijit
命名空间。Dijit 是 Dojo 核心的可选插件。上面的例子需要一个主题以"正确显示"--后面将介绍,现在你可以通过以下语句实现:
<head>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dijit/themes/tundra/tundra.css" />
<script type="text/javascript" charset="utf-8" src="http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojo/dojo.xd.js"
></script>
</head>
<body class="tundra">
<h2>Hello, Dijit</h2>
</body>
我们在网页中添加一个 CSS 文件,并设置 class="tundra"
。这将在网页中使用 'tundra' 主题。Dojo 还提供了两个默认主题 soria 和 nihilo 。主题本质上就是一些 CSS 和图像,你也可以自己创建。
dojo.byId
这是 document.getElementById
函数的快捷方式,但在一些 getElementById
失效的地方也可以使用。dojo.byId
返回 DOM Node,可以直接操作返回结果。dojo.byId 更短更容易键入。
dojo.addOnLoad(function() {
dojo.byId("someNode").innerHTML = "I just replaced the content.";
});
注意上面的代码被封装在 addOnLoad
中,以防止在载入 DOM 前运行代码。
dojo.connect
此函数可关联任何 DOM 事件和任何 node 。Dojo 处理了事件的跨浏览器问题。如下面例子为 node 添加 onclick
事件处理器:
dojo.addOnLoad(function() {
var node = dojo.byId("someNode");
dojo.connect(node, "onclick", function(event) {
console.log("the node was clicked: ", event.target);
});
});
Dojo connect 也可以连接对象。下面的例子设置每次运行 dojo.require()
时都会执行定义的函数:
var handle = dojo.connect(dojo, "require", function(arg) {
console.log("require() called with: ", arg)
dojo.disconnect(handle);
});
dojo.require("dojo.io.iframe");
dojo.connect
传递将提供给回调函数的参数。上面通过一个匿名函数演示了如何使用。对 dojo.connect 返回值调用 dojo.disconnect 可以确保监听器只被调用一次。
dojo.connect 不止可以处理 DOM 事件。所有的方法或函数都可以作为 '事件':
var myObj = {
foo:"bar",
baz: function(e) {
console.log(this.foo);
},
bam: function(e) {
this.foo = "barbar";
}
};
// call myObj.bam() in scope when baz() is run
dojo.connect(myObj, "baz", myObj, "bam");
myObj.baz();
第三个参数 scope 设置了函数作用域。可以向上例一样传入命名函数,也可以使用匿名函数:
var myObj = {
foo:"bar",
baz: function(e){
console.log(this.foo);
},
bam: function(e) {
this.foo = "barbar";
}
};
// call anon function in myObj scope when bam() is run
dojo.connect(myObj, "bam", myObj, function() {
// this is know as "after advice", 和 is run after bam
this.foo = "otherbar";
this.baz();
});
myObj.bam();
Connect 实际使用 dojo.hitch()
以提供作用域转换功能。dojo.hitch()
作用很大。
Topics: dojo.publish, dojo.subscribe
这两个函数可以方便的向匿名对象传递或从匿名对象获取信息。使用 dojo.subscribe()
注册命名通道,然后可以通过对此命名通道使用 dojo.publish()
调用匿名函数。
var subscription = dojo.subscribe("/system/alerts", function(msg) {
console.log(msg);
});
// and later:
dojo.publish("/system/alerts", ["You've been logged out"]);
这可以很方便的实现部分页面的自动更新,而不需了解此页面的其他部分。上例中将 dojo.subscribe
返回值保存在变量中,和 dojo.disconnect
类似,可调用 dojo.unsubscribe
取消注册。
var handle = dojo.subscribe("/foo/bar", function(msg) {
console.log("In this example, I'll never run.")
});
dojo.unsubscribe(handle);
dojo.publish("/foo/bar", ["Baz"]);
Dojo API 中很多地方使用了 Topics 。如 dojo.dnd
(拖拽组件) 中使用了 Topics 以通知如 "/dnd/move/start" 和 "/dnd/move/stop" 这样的匿名事件。Dijit 组件的 dijit.layout.TabContainer
也使用了 Topics 以通知 addChild
, selectChild
, removeChild
等事件。
数组工具
dojo.map
, dojo.filter
, dojo.every
, dojo.some
, dojo.forEach
, dojo.indexOf
等等...Dojo 封装了 JavaScript 1.6 中所有数组工具,为大部分问题提供了functional approach。
最常用的是 forEach
,对数组中每一个元素调用函数:
var arr = ["one","two","three","four"]; dojo.forEach(arr, function(elm, index, theArray) {
// elm is the item in the array:
console.log(elm);
// index is where in the array we are:
console.log('run ', index, ' times');
// theArray is the full array, should you need a reference to it internally:
console.log(elm == theArray[index]);
// should return 'true'
});
第三个参数 scope
是可选的,使用 dojo.hitch
将函数作用范围设置为另一个对象。
var arr = ["one","two","three","four"];
var obj = {
log: function(elm) {
console.log(elm);
}
};
dojo.forEach(arr, function(elm) {
// elm is the item in the array:
this.log(elm);
}, obj);
Filter 根据函数返回值减少数组中的元素数量:
var arr = ["one","two","three","four"];
var newArr = dojo.filter(arr, function(elm, i) {
// only do even numbers:
return i % 2 !== 0;
});
console.log(newArr);
Map 根据函数返回值创建新元素数组:
var arr = ["a","b","c","d"];
var other = ["one", "two", "three", "four"];
var newArr = dojo.map(arr, function(elm, i) {
if(i % 2 == 0) {
// only odds elements from a different array
return other[i];
}
});
console.log(newArr);
indexOf
和 lastIndexOf
返回匹配元素位置,如果没有找到匹配则返回-1:
var arr = ["one","two","three","four","five","one"];
console.log(dojo.indexOf(arr, "two")); // 1
console.log(dojo.lastIndexOf(arr, "one")); // 5
console.log(dojo.indexOf(arr, "one")); // 0
console.log(dojo.indexOf(arr, "unknown")); // -1
DOM 和 CSS 工具
dojo.place
, dojo.clone
, dojo.attr
, dojo.style
, dojo.addClass/removeClass/toggleClass
, dojo.marginBox
, 和 dojo.coords
是 Dojo 提供的部分 DOM 工具,其用法比JavaScript DOM 操作简单。
dojo.place
将在另一个 node 中放置 node :
// place a new <li> as the first in the ul id="miUl":
var li = dojo.doc.createElement('li');
dojo.place(li, "myUl", "first");
// give it some content, too:
li.innerHTML = "Hi!";
dojo.clone
克隆 node,返回新创建的 node:
var input = dojo.query(".cloneMe")[0];
dojo.query("#someButton").onclick(function(e) {
// add a new <input /> every time you click on someButton
dojo.clone(input);
dojo.place(input, e.target, "last");
});
dojo.attr
处理所有跨浏览器的属性设置和获取:
// getter:
dojo.attr("someId", "title"); // title="bar"
// setter, single:
dojo.attr("someId", "title", "A new Title");
// setter, multiple:
dojo.attr("someId", {
"tabindex": 2, // add to tab order
"onclick": function(e) {
// add a click event to this node
}
});
dojo.style
与 dojo.attr
相似,但用于 CSS 样式:
// getter:
dojo.style("someId", "height");
// setter, single:
dojo.style("someId", "padding", "8px");
// setter, multiple:
dojo.style("someId", {
"fontSize": "14pt",
"color": "#333"
});
dojo.addClass
, dojo.removeClass
, dojo.toggleClass
和 dojo.hasClass
用于动态修改 node 的 class=""
属性。所有的上述函数用法相同:传入字符串形式的 ID 或 DOM Node 引用,然后函数作用于 node,或添加或移除 class 名。dojo.hasClass
返回布尔值,如果 node 含有要查询的 class 名则返回 true。
下面语句可在页面中定位 node ,或设置/获取 Node 位置和大小:
// returns x, y, t, l, w, 和 h values of id="someNode"
var pos = dojo.coords("someNode");
console.log(pos);
// includes any potential scroll offsets in t and l values
var abs = dojo.coords("someNode", true);
console.log(abs);
// get just the marginBox, set another node to identical size
var mb = dojo.marginBox("someNode");
dojo.marginBox("otherNode", mb);
Dojo的 DOM 工具函数为常见工作提供简单易用的 API ,并解决跨浏览器带来的麻烦。
dojo.query - Dojo的 CSS3 选择器查询引擎
"获取 DOMNodes 并处理"。
大部分的 Dojo 核心 API 都封装在 dojo.query
中。也就是说,所有可用于单个 node 的 Dojo 函数也可以用于多个匹配 node。如上面的 onclick
例子也可以写成:
dojo.addOnLoad(function() {
dojo.query("#someNode").connect("onclick", function(e) {
console.log('the node dojo.byId("someNode") was clicked', e.target);
});
});
为简化使用,也包含了对 dojo.NodeList
( dojo.query()
返回的数组)使用 .connect()
的简单写法:
dojo.query("#someNode").onclick(function(e) {
console.log('the node dojo.byId("someNode") was clicked', e.target);
});
所有的 DOM Level 2 事件都有简化写法:.onclick
, .onmouseenter
, .onmouseleave
, .onmousemove
, .onmouseover
, .onmouseout
, .onfocus
, .onblur
, .onkeypress
, .onkeydown
, .onkeyup
, .onsubmit
和 .onload
。dojo.query
方法可以嵌套使用,调用后返回相同的 NodeList
对象。
dojo.addOnLoad(function() {
// connect mouseenter and mouseleave functions to all div's with the class "hoverable":
dojo.query("div.hoverable")
.connect("onmouseenter", function(e) {
dojo.style(e.target, "opacity", 1);
})
.connect("onmouseout", function(e) {
dojo.style(e.target, "opacity", 0.42);
})
.style( {
// set the initial opacity to 0.42, as if a mouseout has happened
opacity: 0.42,
// and the color:
backgroundColor:"#ededed"
});
});
扩展 dojo.query
(或"创建插件") 非常容易:
dojo.extend(dojo.NodeList, {
makeItRed: function() {
return this.style({ color:"red" });
},
setColor: function(color) {
return this.style({ color: color });
}
});
// run the makeItRed function across all nodes
dojo.query(".greenNodes").makeItRed();
// set the color: property of .redNodes to a greyish tone:
dojo.query(".redNodes").setColor("#ededed");
有时能直接控制 Node 引用很方便。如你为 div
添加了 onclick
事件处理器,则所有 div
内的 node 都会成为 event.target
(假设 event 传递到 div
)。有时你想像下面那样控制 node:
dojo.query("li").forEach(function(n) {
dojo.connect(n,"onclick",function(e) {
if(n == e.target) {
console.log('same node');
} else {
console.log('bubbling up from different node');
}
// ensure we only ever add the class to the LI element, regardless of target
dojo.addClass(n, "beenClicked");
});
});
Dojo 既没有污染全局命名空间,也没有去抢着占用缩写符号。如果你想为常用功能创建别名或缩写,你可以自己创建。如可用匿名函数为 dojo.query
创建别名:
(function($) {
$("a[href^=http://]").onclick(function(e) {
// confirm all external links before leaving the page
if(!confirm("Visit" + $(e.target).attr("href") + "?")) {
e.preventDefault();
}
});
})(dojo.query);
Dojo 源代码中常常可见下面这样代码:
(function() {
var d = dojo;
d.addOnLoad(function() {
d.connect(d,"loaded",function() {
console.log("obfuscated some");
})
});
})();
JavaScript 是非常灵活的语言。更高级的使用方法请参考 Neil Robert 在 DojoCampus 上发布的 "Creating your Own $" 一文--把所有的 Dojo 工具放到 $ 变量中。
和其他 Dojo 组件一样 dojo.query
/ dojo.NodeList
也秉承"随意使用"的理念。有些特别的方法没有被写入 Base dojo.js
,如果你需要可以通过 dojo.require
使用:
dojo.require("dojo.NodeList-fx"); // adds Animation support to dojo.query
dojo.require("dojox.fx.ext-dojo.NodeList"); // adds DojoX addon Animations to dojo.query
dojo.require("dojo.NodeList-html"); // adds advanced HTML utility functions to dojo.query
这些 package 的命名方法略有不同。'-'表示"跨 package 操作"。如 dojo.NodeList-fx
为 NodeList
增加"fx"功能;但你无法直接调用 dojo.NodeList-fx
。这些方法被加入到 dojo.NodeList
中。dojox.fx.ext-dojo.NodeList
的意思是" DojoX FX 模块扩展 Dojo NodeList 类"。
Ajax: 传输数据
dojo.xhr
提供简单而强大的 Ajax API 。 dojo.xhr()
函数封装了以前版本的方法:dojo.xhrGet
, dojo.xhrPost
, dojo.xhrPut
和 dojo.xhrDelete
。
dojo.xhrGet( {
url:"/path/to/remote.html",
load:functiondata) {
dojo.byId("updateArea").innerHTML = data;
}
});
使用上面的 dojo.xhr
很多任务变得很简单,如通过 GET 命令从服务器中获取远程文件内容并将结果插入到 node 中(见上文),或捕获表单并通过 Ajax 将结果 POST 到服务器上:
<!-- a simple form: -->
<form id="sampleForm" action="submit.php" method="POST">
<input type="text" name="username" />
<button type="submit">login</button>
</form>
<script type="text/javascript">
dojo.addOnLoad(function() {
var form = dojo.byId("sampleForm"); // save ref to form
dojo.connect(form, "onsubmit", function(e) {
// connect to, and disable the submit of this form
e.preventDefault();
// post the form with all it's defaults
dojo.xhrPost( {
form: form,
load: function(data) {
// set the form's HTML to be the response
form.innerHTML = data;
}
});
});
});
</script>
简单的处理 POST 的 PHP 脚本将返回如下结果:
<?php
print "You Sent:";
print_r($_POST);
?>
所有的 dojo.xhr*
方法使用 single object hash 或 property bag 作为唯一的参数,因此不再需要记住参数的顺序--只需记住常用的名称及其用途:
url
: 目标终点。handleAs
: 默认为text
,允许修改回调函数处理收到数据的方式。合法的 built-in 选项有:text
,javascript
,json
, 或xml
timeout
: 等待数据时间,超过此时间仍未收到数据将抛出错误。load
: 数据到达时调用的函数名称。数据作为第一个参数被传递给函数。error
: 错误处理器函数。sync
: 布尔值,表明XMLHttpRequest
是被阻塞还是在后台运行。默认值是false
,表示非同步操作。handle
: 出现错误或者载入成功后调用的函数。传递给函数的对象要么是数据要么是typeof
"Error"。form
:domNode
形式的提交内容 (或字符串形式的 node ID)。如上例所示,从表单action
属性中获得url:
参数。可以通过同时传递form:
和url:
参数改变 URL。content
: 送给 URL 的 JSON 对象。
本文后面讲演示 dojo.hitch
和 dojo.partial
的强大功能,可以方便的控制 load:
, error:
和 handle:
回调函数的作用域。
FX: 灵活且强大的动画 API
Base dojo.js
包含简单的 fade
方法,及强大的 animateProperty
方法(用于添加 CSS 属性动画)。所有动画方法返回 dojo._Animation
实例,使用此对象可以控制动画序列。下面代码闯并运行 fade 动画:
dojo.addOnLoad(function() {
dojo.fadeOut( {
node:"someNode", // a node ref, byId
}).play();
});
dojo._Animation
实例有 play()
, stop()
, status()
, gotoPercent()
, 和 pause()
方法用于控制动画。除了 dojo.anim
都使用 single object hash 定义选项。一些很有用的选项包括:
var anim = dojo.fadeOut( {
node: "someNode", // node to manipulate
duration: 3000, // time in ms to run the animation
easing: function(n) {
// a linear easing function, alter the progression of the curve used
return n;
},
delay: 400, // time in ms to delay the animation when calling .play()
rate: 10 // a framerate like modifier.
});
anim.play();
可选的 dojo.fx.easing
中有超过 30个函数。使用 dojo.require()
即可使用:
dojo.require("dojo.fx.easing");
dojo.addOnLoad(function() {
dojo.fadeOut( {
node:"someNode",
easing: dojo.fx.easing.bounceOut // bounce towards the end of the animation
}).play();
});
上面的函数中也可以在动画进程中发出各种事件。下面是一个例子:
dojo.addOnLoad(function() {
dojo.fadeOut( {
node:"someNode",
beforeBeing: function() {
console.log("the animation will start after I've executed");
},
onBegin: function() {
console.log('the animation just started');
},
onEnd: function() {
console.log('the animation is done now');
},
onPlay: function() {
console.log('the animation was started by calling play()');
},
onStop: function() {
console.log('the animation was stopped');
}
onAnimate: function(val) {
// fired at every step of the animation
console.log('current value: ', val);
}
})
});
最常用的事件是 onEnd
。下面的代码可让某些内容渐出,然后再渐入显示通过 Ajax 获得的替代内容:
var n = dojo.byId("someNode");
dojo.fadeOut( {
node: n,
onEnd: function() {
dojo.xhrGet( {
url: "newContent.html",
load: function(data) {
n.innerHTML = data;
dojo.fadeIn({ node: n }).play();
}
})
}
}).play();
node:
参数既可以是 DOM Node 引用,也可以是将传递给 dojo.byId
的字符串。下面的例子中,我们将引用存为"n"并用于回调函数:
复杂动画中可以使用 dojo.connect
,_Animation
实例就是要连接的对象:
// create a simple loop
var fadein = dojo.fadeIn({ node: "someNode" });
var fadeOut = dojo.fadeOut({ node: "someNode" });
// call fadeout.play() anytime fadein's onEnd is fired:
// and re-play fadein when fadeout's onEnd is fired:
dojo.connect(fadein, "onEnd", fadeout, "play");
dojo.connect(fadeout, "onEnd", fadein, "play");
// start the loop
fadeout.play();
渐入渐出特效很有用,但这只是 dojo.animateProperty
的简单封装实现的。实际是为 opacity 属性设置动画:
// simulate fadeIn
dojo.animateProperty( {
node:"someNode",
properties: {
opacity: 1
}
}).play();
// as opposed to:
// dojo.fadeIn({ node: "someNode" }).play();
animateProperty
更健壮更灵活。通过此函数,可以为一个 node 中的任意多个属性设置动画:
dojo.animateProperty( {
node:"someNode",
properties: {
// end is assumed:
opacity:0,
// define a start and end value:
marginLeft: {
start:5, end:250
}
// start is calculated, use unit "em"
padding: {
end:5, unit:"em"
}
}
}).play();
当然所有的 dojo._Animation
事件和配置选项都有效。properties
hash 接收多种格式。如同时传入 start:
值和 end:
值,node 被强制使用这些属性值。如果只传入 end:
值,则会将当前属性值作为 start:
值。如果只传入一个整数值,则此值将被视为 end:
值。unit:
参数默认为 "px",需要注意的是有些浏览器并不能正确的将 "em" 和 "pt" 值转换为像素数。
注意上面例子中的 marginLeft
。CSS 中此值将是 margin-left:
,但是 JavaScript 中-
是非法的。每个标准的 CSS 属性都有 JavaScript 的 camelCase 版本属性名,如 marginLeft
。
你可能已经注意到 animateProperty
文法比较复杂,如每个例子中都需要调用返回的 _Animation
的 .play()
方法。Base Dojo 中存在方法以简化使用:
dojo.anim("someNode", {
opacity:0,
marginLeft: { start:5, end:250 },
padding: 50
});
上面的例子和以前的例子效果相同。为了方便使用 dojo.anim
而放弃了灵活性,因为现在的参数是有顺序的了。动画将自动被调用 play()
方法。
高级 JavaScript 工具
Dojo 中包含 dojo.declare
和 dojo.mixin
及 prototypical inheritance 函数 dojo.extend
和 dojo.delegate
。还有像 dojo.hitch
和 dojo.partial
这样的作用域操作函数。
Dojo 中最神奇的函数就是 dojo.hitch
,可以创建在其他作用域中运行的函数。
var foo = function() {
var bar = function(arg) {
console.log("was passed: ", arg);
}
dojo.fadeOut( {
node: "nodeById",
onEnd: dojo.hitch(this,"bar")
}).play();
}
这里需要注意的是 hitch 创建的函数没有被立刻执行。上例中,我们在 this
作用域中调用了一个本地函数。DojoCampus 中有几篇很好的关于 dojo.hitch 的文章,详细介绍了 Javascript 作用域操作。
dojo.partial
与 dojo.hitch
类似,不同是 dojo.partial
默认全局作用域。
var style = dojo.partial(dojo.style,"someNodeId");
// anytime we execute this function, we'll style a node with id="someNodeId"
style("opacity",0.5);
style("backgorundColor","#fff");
// it also acts as a getter:
var val = style("width");
console.log(val);
dojo.mixin
的功能是混合多个对象:
var obj = { a: "foo", b: "bar" };
dojo.mixin(obj, { b: "baz", c: "bam" });
console.log(obj);
// Object a=foo b=baz c=bam
上面的例子中删除了重复的b:
。
可以使用 dojo.clone
(也可用于 DOM Node )创建新对象并添加属性:
var obj = { a: "foo", b: "bar" };
var newObj = dojo.clone(obj);
dojo.mixin(newObj, { b: "baz", c: "bam" });
console.log(obj, newObj);
// Object a=foo b=bar Object a=foo b=baz c=bam
Dojo 中使用 declare
创建类。此函数允许使用面向对象方式创建可复用的对象。下面的例子将创建 Person
类和 Person
类实例:
dojo.declare("Person", null, {
constructor: function(nick, name, age) {
this.nick = nick;
this.name = name;
this.age = age;
this.location = null;
},
setLocation:functionloc) {
this.location = loc;
},
getLocation:function) {
return this.location;
}
});
var dante = new Person("dante","Peter Higgins", 28);
dante.setLocation("Tennessee");
console.log(dante.getLocation());
可以在 declare
中创建继承类。下例中 Employee
类继承 Person
类。Employee 包含更多的数据成员:
dojo.declare("Person", null, {
constructor: function(nick, name, age) {
this.nick = nick;
this.name = name;
this.age = age;
this.location = null;
},
setLocation:functionloc) {
this.location = loc;
},
getLocation:function) {
return this.location;
}
});
dojo.declare("Employee", Person, {
employeeId: 0,
setId: function(id) {
this.employeeId = id;
}
})
// I am employed:
var dante = new Employee("dante","Peter Higgins", 28);
dante.setLocation("Tennessee");
dante.setId(42);
console.log(dante.employeeId);
这样就可以创建 People 和 Employee,并通过属性和方法区分。
通过 dojo.mixin
可为类的实例添加自定义的属性:
dojo.declare("Person", null, {
constructor: function(nick, name, age) {
this.nick = nick;
this.name = name;
this.age = age;
this.location = null;
}
});
var dante = new Person("dante","Peter Higgins", 28);
dojo.mixin(dante, {
employeeId: 42
});
console.log(dante.employeeId); // 42
使用 dojo.extend
可以直接修改类。使用 extend()
后所有实例都可以使用扩展属性:
dojo.declare("Person", null, {
constructor: function(nick, name, age) {
this.nick = nick;
this.name = name;
this.age = age;
this.location = null;
}
});
// add Eye-color functions to the Person Class
dojo.extend(Person, {
eyeColor:"adefault",
setEyeColor: function(color) {
this.eyeColor = color;
}
});
var dante = new Person("dante","Peter Higgins", 28);
console.log(dante.eyeColor); // default
dante.setEyeColor("brown");
console.log(dante.eyeColor); // brown
dojo.declare
, dojo.mixin
和 dojo.extend
提供的灵活性适用于整个 Dojo 工具包。你可以尽情修改、重用、扩充 Dojo, Dijit, 及 DojoX 。如所有的 Dijit 类都继承自名为 dijit._Widget
的基类。
Built-in 命名空间支持
再也不用担心代码的位置了!dojo, dijit, 和 dojox 命名空间都是同一级文件夹,位于 ../namespace (相对于 dojo/)。你可以通过创建文件夹封装你的代码并创建自定义的命名空间:
+ dojo-1.2/
+ dojo/
+ dojo.js
+ dijit/
+ dojox/
+ custom/
+ kernel.js
只需要使用 dojo.provide()
通知 Dojo 。在 dojo-1.2/custom/kernel.js中:
dojo.provide("custom.kernel");
dojo.require("dojo.io.iframe");
custom.init = function() {
// comments get removed as part of the Build process
console.log("I am custom code!");
}
dojo.addOnLoad(custom.init);
在网页中只需要 dojo.require
你的 package:
dojo.require("custom.kernel");
如果想把你的代码放在 dojo-1.2 文件夹之外,只需要注册相对于 dojo.js
的路径:
+ dojo-1.2/
+ dojo/
+ dojo.js
+ dijit/
+ dojox/
+ custom/
+ templates/
+ Template.html
+ kernel.js
在你的 HTML 中,注册路径。上例注册代码为:
dojo.registerModulePath("custom", "../../custom");
dojo.require("custom.kernel");
最重要的就是在你的 Web 服务器中定位 dojo.js
。然后一切就OK了。注册了模块路径后,就可以轻松的访问那个路径中的任意文件:
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.declare("custom.Widget", [dijit._Widget, dijit._Templated], {
templatePath: dojo.moduleUrl("custom", "templates/Template.html");
});
总结
此教程粗略的介绍了如何使用 Dojo 工具包帮助开发网页。欲了解更多,请访问 Dojo 网站。Dojo 不仅有免费的社区支持 ( Dojo 网站,irc.freenode.net 中的 #dojo ,及 DojoCampus);Dojo 还有收费的商业支持,如 SitePen。Dojo 也获得了很多主流互联网企业的支持。我们希望您积极参与以帮助我们改进Dojo。