Dojo工具包简介
简述
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", "http://www.cnblogs.com/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。