“modern”dojo
声明:本文是基于dojo官方文档,加上自己的理解整理出来的。
本文会简单介绍一下,dojo1.10带来的新的变化。
准备开始
Dojo1.7是一个重要里程碑,整体的架构更加灵活,也更加“现代化”。Dojo1.10则在1.7的基础上,引入了一些新的特性和概念,例如dojo/on
。如果你想让dojo代码跑的更快,更加高效,并且想提高代码的可维护性,那就赶紧升级到dojo1.10吧。另外,dojo是完全向后兼容的。
新hello world
modern dojo其中一个核心概念是:禁止使用全局命名空间。dojo为了向后兼容,原先放置在全局命名空间中的函数和变量,仍然是可用的,但在新版的dojo中,最好别用。因为其他开发人员随时可能自己定义一个名字跟全局命名空间中的函数名一样的函数出来,这样会造成冲突的。像下面的使用方式就不推荐。
dojo.* or dijit.* or dojox.*
其实只需简单的引入dojo.js
,然后使用require()
方法加载其他模块即可。
另一个核心概念是:同步操作慢,异步操作快。dojo 1.7(包括1.7),支持Asynchronous Module Definition (AMD)的概念,可以使用require()
来异步加载用到的dojo 模块。
旧版用法
dojo.ready(function(){
dojo.byId("helloworld").innerHTML = "Hello World!";
});
新版用法
require(["dojo/dom", "dojo/domReady!"], function(dom){
dom.byId("helloworld").innerHTML = "Hello New World!";
});
其中的require
方法有两个参数,第一个是模块id列表,另一个是函数,在这个函数会存放模块的引用。
细心的读者会发现dojo/doReady!
是没法在函数中引用的,原因是,dojo/doReady!
是一个dojo插件,它会与dojo的加载器进行交互,保证页面中的dom结构都解析完毕后,函数才开始调用。如果你需要使用dojo操作dom,那么最好使用该插件。
Dojo基础以及核心
在旧版本的dojo
中,dojo.js是一个臃肿庞大的脚本,里面存放了非常多的dojo方法。所以我们应该尽量避免使用dojo.*
的方式。
dojoconfig
对象中有一个async
属性,默认值是false
,这意味着,当使用dojo时,所有dojo基础模块将会被加载。为了提高应用的响应速度,可以把async设置为true,这样这些基础模块不会被自动的加载到。
由于旧版的dojo.js过于庞大,新版的dojo中,已经将里面的代码模块化,使用方式也不同了。如下:
旧的用法
dojo.require("dojo.string");
dojo.byId("someNode").innerHTML = dojo.string.trim(" I Like Trim Strings ");
新的用法
require(["dojo/dom", "dojo/string", "dojo/domReady!"], function(dom, string){
dom.byId("someNode").innerHTML = string.trim(" I Like Trim Strings ");
});
事件以及切面
在”modern dojo”中,dojo/on
用于事件处理,用来代替原来的dojo.connect()
, 而dojo/aspect
则运用了AOP的概念,可以进行方法的拦截。
旧版用法
<script>
dojo.require("dijit.form.Button");
myOnClick = function(evt){
console.log("I was clicked");
};
dojo.connect(dojo.byId("button3"), "onclick", myOnClick);
</script>
<body>
<div>
<button id="button1" type="button" onclick="myOnClick">Button1</button>
<button id="button2" data-dojo-type="dijit.form.Button" type="button"
data-dojo-props="onClick: myOnClick">Button2</button>
<button id="button3" type="button">Button3</button>
<button id="button4" data-dojo-type="dijit.form.Button" type="button">
<span>Button4</span>
<script type="dojo/connect" data-dojo-event="onClick">
console.log("I was clicked");
</script>
</div>
</body>
modern dojo用法
<script>
require([
"dojo/dom",
"dojo/on",
"dojo/parser",
"dijit/registry",
"dijit/form/Button",
"dojo/domReady!"
], function(dom, on, parser, registry){
var myClick = function(evt){
console.log("I was clicked");
};
parser.parse();
on(dom.byId("button1"), "click", myClick);
on(registry.byId("button2"), "click", myClick);
});
</script>
<body>
<div>
<button id="button1" type="button">Button1</button>
<button id="button2" data-dojo-type="dijit/form/Button" type="button">Button2</button>
<button id="button3" data-dojo-type="dijit/form/Button" type="button">
<div>Button4</div>
<script type="dojo/on" data-dojo-event="click">
console.log("I was clicked");
</script>
</button>
</div>
</body>
在旧版的dojo中,如果你想在某个js方法执行后,执行某个方法,可以如下这样做:
var callback = function(){
// ...
};
//myInstance表示目标对象,execute表示目标对象中的方法,callback表示,execute执行后需要调用的方法。
var handle = dojo.connect(myInstance, "execute", callback);
// ...
dojo.disconnect(handle);
modern dojo可以使用切面。
require(["dojo/aspect"], function(aspect){
var callback = function(){
// ...
};
var handle = aspect.after(myInstance, "execute", callback);
// ...
handle.remove();
});
发布与订阅
发布订阅自1.7版本便开始有了,后续版本又做了一些改进。
旧版用法
// To publish a topic
dojo.publish("some/topic", [1, 2, 3]);
// To subscribe to a topic
var handle = dojo.subscribe("some/topic", context, callback);
// And to unsubscribe from a topic
dojo.unsubscribe(handle);
新版用法
require(["dojo/topic"], function(topic){
// To publish a topic
topic.publish("some/topic", 1, 2, 3);
// To subscribe to a topic
var handle = topic.subscribe("some/topic", function(arg1, arg2, arg3){
// ...
});
// To unsubscribe from a topic
handle.remove();
});
下面具体举个例子
require(["dojo/topic", "dojo/dom", "dojo/on", "dojo/domReady!"],
function(topic, dom, on){
var handle = topic.subscribe("some/topic", function(e){
dom.byId("output").innerHTML = "I received: " + e.msg;
handle.remove();
});
on(dom.byId("publish"), "click", function(){
topic.publish("some/topic", { msg: "hello world" });
});
});
<button type="button" id="publish">Publish "some/topic"</button>
<div id="output">Nothing Yet...</div>
Dojo异步编程
可以使用Deferred
和 promise
api来处理。
旧版用法
function createMyDeferred(){
var myDeferred = new dojo.Deferred();
setTimeout(function(){
myDeferred.callback({ success: true });
}, 1000);
return myDeferred;
}
var deferred = createMyDeferred();
deferred.addCallback(function(data){
console.log("Success: " + data);
});
deferred.addErrback(function(err){
console.log("Error: " + err);
});
新版用法
require(["dojo/Deferred"], function(Deferred){
function createMyDeferred(){
var myDeferred = new Deferred();
setTimeout(function(){
myDeferred.resolve({ success: true });
}, 1000);
return myDeferred;
}
var deferred = createMyDeferred();
deferred.then(function(data){
console.log("Success: " + data);
}, function(err){
console.log("Error: " + err);
});
});
发送Ajax请求
旧版用法
dojo.xhrGet({
url: "something.json",
handleAs: "json",
load: function(response){
console.log("response:", response);
},
error: function(err){
console.log("error:", err);
}
});
新版用法
require(["dojo/request"], function(request){
request.get("something.json", {
handleAs: "json"
}).then(function(response){
console.log("response:", response);
}, function(err){
console.log("error:", err);
});
});
操作Dom的模块
模块 |
---|
dojo/dom |
dojo/dom-attr |
dojo/dom-class |
dojo/dom-construct |
dojo/dom-form |
dojo/io-query |
dojo/dom-geometry |
dojo/dom-prop |
dojo/dom-style |
require(["dojo/dom", "dojo/dom-attr"], function(dom, domAttr){
var node = dom.byId("someNode");
// Retrieves the value of the "value" DOM attribute
var value = domAttr.get(node, "value");
// Sets the value of the "value" DOM attribute
domAttr.set(node, "value", "something");
});
Dijit and Widgets
如果你想观察某个元素属性值的变化,可以使用dojo/Stateful
中的类。
require(["dijit/form/Button", "dojo/domReady!"], function(Button){
var button = new Button({
label: "A label"
}, "someNode");
// 在button.label上设置一个观察者
var handle = button.watch("label", function(attr, oldValue, newValue){
console.log("button." + attr + " changed from '" + oldValue + "' to '" + newValue + "'");
});
// 获取当前label
var label = button.get("label");
console.log("button's current label: " + label);
// 值发生改变,调用观察者
button.set("label", "A different label");
handle.unwatch();
button.set("label", "Even more different");
});
Parser
在dojo1.10里,可以显示的使用解析器,无需在dojo config里配置parseOnLoad: true
。
require(["dojo/parser", "dojo/domReady!"], function(parser){
parser.parse();
});
另外使用data-dojo-type
替代dojoType
,至于元素的属性则可以使用data-dojo-props
来指定。
<button data-dojo-type="dijit/form/Button" tabIndex=2
data-dojo-props="iconClass: 'checkmark'">OK</button>
1.10中,你可以向下面这样监听元素属性的变化。
<button data-dojo-type="dijit/form/Button" type="button">
<span>Click</span>
<script type="dojo/on" data-dojo-event="click" data-dojo-args="e">
console.log("I was clicked!", e);
this.set("label", "Clicked!");
</script>
<script type="dojo/watch" data-dojo-prop="label" data-dojo-args="prop, oldValue, newValue">
console.log("button: " + prop + " changed from '" + oldValue + "' to '" + newValue + "'");
</script>
</button>
本文到此完结。