|
首先接触到的,是dojo的Event System。 以前,我们是由页面控件触发一系列时间的时候,整个事件链要先定义好,然后才能按需要调用已经写好的调用模块,一旦要修改事件链,就不是那么容易了。由一个函数调用另一个函数,能随便说要调用哪个吗?能在运行的时候很容易修改吗?除了那些大师级的人物,我相信我们这些菜鸟要解决这些问题,要费不少事。 在dojo中,其关注的事件不仅仅是Dom事件,它把任何的js方法调用都看作可以侦听的事件,这就把一切都统一到一个地方了。 我们都写过这样的代码:
1
var
buttonNode
=
document.getElementById(
"
button
"
);
2
function
foo()
3
{
4
alert(
"
foo
"
);
5
}
6
buttonNode.onclick
=
function
()
7
{
8
foo();
9
}
要调用foo函数,需要这么写,如果说接着我还要调用一个函数呢?那么,就需要重写buttonNode的onclick事件函数,把以前的都再写一遍,如果我还要再调用呢。。。。 我们来看看dojo中是怎么解决的,看下面的一句
1
dojo.event.connect(buttonNode,
"
onclick
"
,
"
foo
"
);
就这么一句,就绑定了触发函数,想再加?那就继续用dojo.event.connect(buttonNode,"onclick","foo2")... 还有这么一种写法:
dojo.event.connect(handlerNode,
"
onclick
"
,
function
(evt){
//
});
上面是buttonNode绑定一个函数,如果要与某对象的某个函数绑定的话,就用
dojo.event.connect(buttonNode,
"
onclick
"
, object,
"
handler
"
);
object是目标对象,handler是目标对象的函数,这里要注意,object不仅仅是页面控件,一切对象皆可行,就又回到“关注的事件不仅仅是Dom事件,它把任何的js方法调用都看作可以侦听的事件”。要解除绑定的话,就可以使用dojo的disconnect方法,调用参数一定要与connect一致,即可解除之前的绑定操作。 dojo中connect函数的参数有下面几种:
- 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
最后一句的作用是什么?使得执行exampleObj的foo函数之后,执行exampleObj的bar函数,一切对象皆可绑定! 为了防止不经意间对事件的多处绑定,造成连锁调用。Dojo提供关键字链绑定,比如可以只绑定一次:
1
dojo.event.kwConnect({
2
srcObj: exampleObj,
3
srcFunc:
"
foo
"
,
4
targetObj: exampleObj,
5
targetFunc:
"
bar
"
,
6
once:
true
7
});
同样,对应也提供了一个kwDisconnect()方法来进行关键字绑定的解除。 在connect()和KwConnect()中,可以实现延迟执行和循环执行。 KwConnect()中,只需要加一个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
>
由上面的延迟,可以想到,如果目标等于源的话,那么就是一个循环执行! 据说在connect()中,延迟信息在它的第九个参数,具体怎么样,我还没去试。 上面是在事件发生后调用目标,如果要在发生前呢?就是下面的东西了:
dojo.event.connect(
"
before
"
, exampleObj,
"
foo
"
, exampleObj,
"
bar
"
);
很容易理解吧,我就不多说了。在KwConnect中,就是
dojo.event.kwConnect({ type:
"
before
"
, srcObj: exampleObj, srcFunc:
"
foo
"
, targetObj: exampleObj, targetFunc:
"
bar
"
});
默认情况下,connect()中第一个参数就是"after"了,同理KwConnect中的type默认是"after"。 下面要说的是方法包装。当我们想改变方法的输入输出时,一般情况下是直接去修改代码,那么,如果不修改原方法怎么办呢?在dojo中,也给出了解决方法,就是用Around advice包装方法。下面是一个例子:
<
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
>
结果是4,如果取消注释,则结果为"sss",开始调用的时候,只传了个参数1,经过包装处理,添加了一个默认参数,然后继续,函数执行完毕后,还可以将输出结果再处理一遍,当然,只是在函数有返回值的时候。 这里要注意的是:函数aroundFoo有且只能有一个参数,就是要改变的方法对象。这样,每次执行foo函数时,都会进行包装,然后再输出。 利用connect()的时候,有一个问题就是参数传递,参数不一致,该怎么办?先看下面一段:
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
>
结果是怎样的呢?2个连接的函数的参数相同!所以,要传递参数到另外一个函数中,已经不需要我们多做什么,dojo已经传过去了,参数的格式不一致的话,我们只需要再包装一下目标函数。 网上的那个例子我怎么也调试不成功,花了点时间,改了下,终于好了,下面是代码:
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个参数
13
alert(
"
1:
"
+
arg1
+
"
"
+
arg2);
14
}
15
};
16
17
var
obj2
=
{
18
oneArgFunc:
function
(arg1){
19
//
只需要一个数组作为参数
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不能少,少了就触发不了了,照道理默认就是after的啊,具体可能是dojo内部问题吧。 接下来介绍匿名通信。 对象之间,不可能总是互相可见的,可能要连接的对象不是同时产生的,也就是说,异步产生,这样的话,用connect()就不是那么方便了,什么时候connect(),就是个问题了。dojo中,"Topics to the rescue!",dojo是利用topic机制来解决的。看下面的代码
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
由上面可以看到,连接是分步进行的。在前面说明,要连接一个对象,具体是哪个,它可以不用知道,后面,可以指定一个连接对象,这样,2个连接的对象,不知道对方是谁,因为它们是通过发布/订阅机制通信,是通过中转的。这么做有什么好处?不用我说了吧。这就是匿名通信。 |