2009年5月22日星期五

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.requiredojo.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);

indexOflastIndexOf 返回匹配元素位置,如果没有找到匹配则返回-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.styledojo.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.toggleClassdojo.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.onloaddojo.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-fxNodeList增加"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.xhrPutdojo.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.hitchdojo.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.declaredojo.mixin 及 prototypical inheritance 函数 dojo.extenddojo.delegate 。还有像 dojo.hitchdojo.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.partialdojo.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.mixindojo.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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值