最近發(fā)現(xiàn)ajax很不錯(cuò),由于它的存在,b/s結(jié)構(gòu)的應(yīng)用,在使用上與c/s結(jié)構(gòu)的更接近了。至于什么是ajax,這就不是我所要說明的,不清楚的自己去網(wǎng)上搜索。
由于看ajax的東西,進(jìn)而找到幾個(gè)與此相關(guān)的框架。由于我是做java的,一般用eclipse,eclipse的編輯javascript的插件 JSEclipse中,有對dojo的支持,而我以前看的eclipse中對ajax的支持框架中也有dojo,所以,我就研究dojo了。
首先,當(dāng)然是把整個(gè)框架下載下來,在http://dojotoolkit.org/download/里就可以下載到最近的dojo了。下完后,看了下demo,就開始滿互連網(wǎng)的搜索關(guān)于dojo的東西,發(fā)現(xiàn)還真是不多,而且不是講得很清楚,于是,就有想寫點(diǎn)東西了。
首先接觸到的,是dojo的Event System。
以前,我們是由頁面控件觸發(fā)一系列時(shí)間的時(shí)候,整個(gè)事件鏈要先定義好,然后才能按需要調(diào)用已經(jīng)寫好的調(diào)用模塊,一旦要修改事件鏈,就不是那么容易了。由 一個(gè)函數(shù)調(diào)用另一個(gè)函數(shù),能隨便說要調(diào)用哪個(gè)嗎?能在運(yùn)行的時(shí)候很容易修改嗎?除了那些大師級的人物,我相信我們這些菜鳥要解決這些問題,要費(fèi)不少事。
在dojo中,其關(guān)注的事件不僅僅是Dom事件,它把任何的js方法調(diào)用都看作可以偵聽的事件,這就把一切都統(tǒng)一到一個(gè)地方了。
我們都寫過這樣的代碼:
1 var buttonNode= document.getElementById("button");
2 function foo()
3 {
4 alert("foo");
5 }
6 buttonNode.onclick = function()
7 {
8 foo();
9 }
要調(diào)用foo函數(shù),需要這么寫,如果說接著我還要調(diào)用一個(gè)函數(shù)呢?那么,就需要重寫buttonNode的onclick事件函數(shù),把以前的都再寫一遍,如果我還要再調(diào)用呢。。。。
我們來看看dojo中是怎么解決的,看下面的一句
1 dojo.event.connect(buttonNode,"onclick","foo");
就這么一句,就綁定了觸發(fā)函數(shù),想再加?那就繼續(xù)用dojo.event.connect(buttonNode,"onclick","foo2")...
還有這么一種寫法:
dojo.event.connect(handlerNode, "onclick", function(evt){
//
});
上面是buttonNode綁定一個(gè)函數(shù),如果要與某對象的某個(gè)函數(shù)綁定的話,就用
dojo.event.connect(buttonNode, "onclick", object, "handler");
object是目標(biāo)對象,handler是目標(biāo)對象的函數(shù),這里要注意,object不僅僅是頁面控件,一切對象皆可行,就又回到“關(guān)注的事 件不僅僅是Dom事件,它把任何的js方法調(diào)用都看作可以偵聽的事件”。要解除綁定的話,就可以使用dojo的disconnect方法,調(diào)用參數(shù)一定要 與connect一致,即可解除之前的綁定操作。
dojo中connect函數(shù)的參數(shù)有下面幾種:
- object, name, name
- object, name, function pointer
- object, name, object, name
再看看這段:
1 var exampleObj = {
2 counter: 0,
3 foo: function(){
4 alert("foo");
5 this.counter++;
6 },
7 bar: function(){
8 alert("bar");
9 this.counter++;
10 }
11 };
12
13 dojo.event.connect(exampleObj, "foo", exampleObj, "bar");
14
15
最后一句的作用是什么?使得執(zhí)行exampleObj的foo函數(shù)之后,執(zhí)行exampleObj的bar函數(shù),一切對象皆可綁定!
為了防止不經(jīng)意間對事件的多處綁定,造成連鎖調(diào)用。Dojo提供關(guān)鍵字鏈綁定,比如可以只綁定一次:
1 dojo.event.kwConnect({
2 srcObj: exampleObj,
3 srcFunc: "foo",
4 targetObj: exampleObj,
5 targetFunc: "bar",
6 once: true
7 });
同樣,對應(yīng)也提供了一個(gè)kwDisconnect()方法來進(jìn)行關(guān)鍵字綁定的解除。
在connect()和KwConnect()中,可以實(shí)現(xiàn)延遲執(zhí)行和循環(huán)執(zhí)行。
KwConnect()中,只需要加一個(gè)delay屬性就可以了,測試代碼如下:
1 <HTML>
2 <HEAD>
3 <TITLE> New Document </TITLE>
4 <META NAME="Generator" CONTENT="EditPlus">
5 <META NAME="Author" CONTENT="">
6 <META NAME="Keywords" CONTENT="">
7 <META NAME="Description" CONTENT="">
8 <script type="text/javascript" src="dojo.js"></script>
9
10 </HEAD>
11
12 <BODY>
13 <INPUT TYPE="button" id="eee" value="test">
14 <script language="javascript">
15
16 var exampleObj = {
17 counter: 0,
18 foo: function(){
19 alert("foo");
20 this.counter++;
21 },
22 bar: function(){
23 alert("bar");
24 this.counter++;
25 }
26 };
27
28 dojo.event.kwConnect({
29 srcObj: exampleObj,
30 srcFunc: "foo",
31 targetObj: exampleObj,
32 targetFunc: "bar",
33 delay: 3000
34 });
35 dojo.event.connect(document.getElementById("eee"),"onclick",exampleObj,"foo");
36
37
38 </script>
39 </BODY>
40 </HTML>
由上面的延遲,可以想到,如果目標(biāo)等于源的話,那么就是一個(gè)循環(huán)執(zhí)行!
據(jù)說在connect()中,延遲信息在它的第九個(gè)參數(shù),具體怎么樣,我還沒去試。
上面是在事件發(fā)生后調(diào)用目標(biāo),如果要在發(fā)生前呢?就是下面的東西了:
dojo.event.connect("before", exampleObj, "foo", exampleObj, "bar");
很容易理解吧,我就不多說了。在KwConnect中,就是
dojo.event.kwConnect({
type: "before",
srcObj: exampleObj,
srcFunc: "foo",
targetObj: exampleObj,
targetFunc: "bar"
});
默認(rèn)情況下,connect()中第一個(gè)參數(shù)就是"after"了,同理KwConnect中的type默認(rèn)是"after"。
下面要說的是方法包裝。當(dāng)我們想改變方法的輸入輸出時(shí),一般情況下是直接去修改代碼,那么,如果不修改原方法怎么辦呢?在dojo中,也給出了解決方法,就是用Around advice包裝方法。下面是一個(gè)例子:
<HEAD>
<TITLE> New Document </TITLE>
<script type="text/javascript" src="dojo.js"></script>
</HEAD>
<BODY>
<INPUT TYPE="button" id="eee" value="test">
<script language="javascript">
function foo(arg1, arg2)
{
return arg1+arg2;
}
function aroundFoo(invocation){
if(invocation.args.length < 2){
invocation.args.push(3);
}
var result = invocation.proceed();
//result="sss";
return result;
}
dojo.event.connect("around", "foo", "aroundFoo");
dojo.event.connect(document.getElementById("eee"),"onclick",function(){alert(foo(1))});
</script>
</BODY>
</HTML>
結(jié)果是4,如果取消注釋,則結(jié)果為"sss",開始調(diào)用的時(shí)候,只傳了個(gè)參數(shù)1,經(jīng)過包裝處理,添加了一個(gè)默認(rèn)參數(shù),然后繼續(xù),函數(shù)執(zhí)行完畢后,還可以將輸出結(jié)果再處理一遍,當(dāng)然,只是在函數(shù)有返回值的時(shí)候。
這里要注意的是:函數(shù)aroundFoo有且只能有一個(gè)參數(shù),就是要改變的方法對象。這樣,每次執(zhí)行foo函數(shù)時(shí),都會(huì)進(jìn)行包裝,然后再輸出。
利用connect()的時(shí)候,有一個(gè)問題就是參數(shù)傳遞,參數(shù)不一致,該怎么辦?先看下面一段:
1 <HTML>
2 <HEAD>
3 <TITLE> New Document </TITLE>
4 <script type="text/javascript" src="dojo.js"></script>
5 </HEAD><BODY>
6 <script language="javascript">
7 var obj1 = {
8 twoArgFunc: function(arg1, arg2){
9 alert("1:"+arg1+" "+arg2);
10 }
11 };
12
13 var obj2 = {
14 oneArgFunc: function(arg1,arg2){
15 alert("2:"+arg1+" "+arg2);
16 }
17 };
18
19 dojo.event.connect(obj1, "twoArgFunc",
20 obj2, "oneArgFunc");
21
22 obj1.twoArgFunc(1,4);
23 </script>
24 </BODY>
25 </HTML>
結(jié)果是怎樣的呢?2個(gè)連接的函數(shù)的參數(shù)相同!所以,要傳遞參數(shù)到另外一個(gè)函數(shù)中,已經(jīng)不需要我們多做什么,dojo已經(jīng)傳過去了,參數(shù)的格式不一致的話,我們只需要再包裝一下目標(biāo)函數(shù)。
網(wǎng)上的那個(gè)例子我怎么也調(diào)試不成功,花了點(diǎn)時(shí)間,改了下,終于好了,下面是代碼:
1 <HTML>
2 <HEAD>
3 <TITLE> New Document </TITLE>
4 <script type="text/javascript" src="dojo.js"></script>
5
6 </HEAD>
7
8 <BODY>
9 <script language="javascript">
10 var obj1 = {
11 twoArgFunc: function(arg1, arg2){
12 // 需要2個(gè)參數(shù)
13 alert("1: "+arg1+" "+arg2);
14 }
15 };
16
17 var obj2 = {
18 oneArgFunc: function(arg1){
19 //只需要一個(gè)數(shù)組作為參數(shù)
20 alert("2: "+arg1);
21 }
22 };
23
24 function aroundFunc(invocation){
25 var tmpArgs = [
26 invocation.args[0],
27 invocation.args[1]
28 ];
29 invocation.args = [tmpArgs];
30 return invocation.proceed();
31 }
32
33 // after-around advice
34 dojo.event.connect("after",obj1, "twoArgFunc",obj2, "oneArgFunc","aroundFunc");
35
36 //也可以寫成下面2句
37 //dojo.event.connect(obj1, "twoArgFunc",obj2, "oneArgFunc");
38 //dojo.event.connect("around",obj2,"oneArgFunc","aroundFunc");
39
40 obj1.twoArgFunc(1,4);
41 </script>
42 </BODY>
43 </HTML>
44
要注意的是,34行的after不能少,少了就觸發(fā)不了了,照道理默認(rèn)就是after的啊,具體可能是dojo內(nèi)部問題吧。
接下來介紹匿名通信。
對象之間,不可能總是互相可見的,可能要連接的對象不是同時(shí)產(chǎn)生的,也就是說,異步產(chǎn)生,這樣的話,用connect()就不是那么方便了,什么時(shí)候 connect(),就是個(gè)問題了。dojo中,"Topics to the rescue!",dojo是利用topic機(jī)制來解決的??聪旅娴拇a
1 var exampleObj = {
2 counter: 0,
3 foo: function(){
4 alert("foo");
5 this.counter++;
6 },
7 bar: function(){
8 alert("bar");
9 this.counter++;
10 }
11 };
12
13 // previously we used this connect syntax
14 //
15 // dojo.event.connect(exampleObj, "foo", exampleObj, "bar");
16 //
17 // which we now replace with:
18
19 // set up our publisher
20 dojo.event.topic.registerPublisher("/example", exampleObj, "foo");
21
22 // and at some point later, register our listener
23 dojo.event.topic.subscribe("/example", exampleObj, "bar");
24
25
由上面可以看到,連接是分步進(jìn)行的。在前面說明,要連接一個(gè)對象,具體是哪個(gè),它可以不用知道,后面,可以指定一個(gè)連接對象,這樣,2個(gè)連接的對象,不知道對方是誰,因?yàn)樗鼈兪峭ㄟ^發(fā)布/訂閱機(jī)制通信,是通過中轉(zhuǎn)的。這么做有什么好處?不用我說了吧。這就是匿名通信。