不做浮躁的人
正在行走的人...
posts - 171,  comments - 51,  trackbacks - 0

EventExamples

Version 36, changed by bill@dojotoolkit.org05/07/2006.   Show version history

Notes and examples on the Dojo event system, by Dylan Schiemann

Purpose

The Dojo event system is designed to provide a unified event system for both DOM events and programmatic events, with an AOP (aspect oriented programming) style advice mechanism, without creating extra burden on developers who want to use the most common simple DOM event mechanism.

dojoAttachEvent

dojoAttachEvent allows you to specify DOM event handlers in a very concise manner:

dojo.webui.widgets.Foo = function() {

...

  this.templateString = '<div dojoAttachPoint="divNode"
    dojoAttachEvent="onClick; onMouseOver: onFoo;"></div>';
 }

In other words, for a widget that contains the above templateString, there is a div node, that will listen for onclick and onmouseover DOM events. The onclick event will be routed to a handler called onClick for that widget, while the onmouseover event will be routed to handler onFoo:

dojo.webui.widgets.Foo = function() {

...

  this.onClick = function(evt) {
  // do something when clicking on the div for this widget
  }

  this.onFoo = function(evt) {
    // do something else when mousing over the div for
    // this widget
  }

...

}

Note that onFoo and onClick are just arbitrary names of methods in the widget. The limitation of dojoAttachEvent is that it only currently works for binding from DOM events.


dojo.event.connect

dojo.event.connect is a mechanism for connecting a dom event or method call to another event handler or method call:

dojo.webui.widgets.Foo = function() {

...

  dojo.event.connect(this.divNode, "onclick", this, "onClick");
  dojo.event.connect(this, "onClick", this, "onFoo");
  dojo.event.connect(widgetBar, "onBar", this, "onFoo");

...

}

The first connect method above does the same thing as the example above defined with dojoAttachEvent. The second one is more interesting, as it connects the onClick handler method to another method called onFoo. What this means is that it is possible to connect any two methods, and pass the arguments from the first method to the second one. The third example shows how you might connect any two method from any two objects.





Adding a New Handler "Before" Any Existing

You can force your new handler to run before previously installed ones using kwConnect. For example to install myFunction as a new onclick event handler for myObject, you could do:



dojo.event.kwConnect
  ({type: "before", srcObj: myObject, srcFunc: "onclick",
    adviceFunc: myFunction});




Advice

dojo.event.connect is very useful, but what if the argument structure of the two methods do not match? This is where AOP style advice becomes useful. Advice allows intercession, i.e. it allows us to alter behavior at runtime.

dojo.webui.widgets.Foo = function() {

...

  dojo.event.connect("after", this, "onClick", this,
    "onHandleClick", this, "aroundObject");

  this.aroundObject = function(mi) {
    mi.args[0] = "foo";
    if(mi.args[1]){
      mi.args[1] = "bar";
    }
    mi.args[2] = "baz";
    return mi.proceed();
  }

  this.onClick = function(evt) {
    // dom something onClick
  }

  this.onHandleClick = function(arg0, arg1, arg2) {
    // do something else, for example, maybe make a call
    // to dojo.io.bind to make a POST request, or grab an
    // arbitrary data fragment from the server
  }

...

}

The advice object contains an arguments array that is prepoulated from the first functions arguments, and then rewrites the arguments after the first function is completed, before passing these arguments to the second object. Hence the term "after" for the first parameter, which specifies the type of advice.



Advice can also be used to intercept and modify the arguments of a method before it is called, and need not even be connected to a second method:

dojo.webui.widgets.Foo = function() {

...

  dojo.event.connect("around", this, "onHandleClick",
    this, "aroundObject");

  // mi is an abbreviation for \MethodInvocation
  this.aroundObject = function(mi) {
    mi.args[0] = "foo";
    if(mi.args[1]){
      mi.args[1] = "bar";
    }
    mi.args[2] = "baz";
    return mi.proceed();
  }

  this.onHandleClick = function(arg0, arg1, arg2) {

  }

...

}

Dojo's advice system was based on BurstLib's MOP implemetation



dojo.event.kwConnect

dojo.event.kwConnect (the kw follows the standard Python convention for the phrase: key words) allows you to specify connect through an object literal rather than through a traditional method call. This is useful in the case of having a large number of parameters that would otherwise be null. For example, instead of :

dojo.event.connect("after", this, "onClick", this,
  "onHandleClick", this, "aroundObject"):

... you would instead do something like:

dojo.event.kwConnect({
  srcObj: this,
  srcFunc: "onClick",
  adviceObj:  this,
  adviceFunc: "onHandleClick",
  aroundObj: this,
  aroundFunc: "aroundObject",
  adviceType: "after"
});

dojo.event.topic

Say you have a case where you have a number of widgets in a document, and you want them all to be able to listen for the same event, and also push events to the other widgets that are listening. With the normal dojo.event.connect, you would need to create a connection between each set of widgets manually. Instead, you just do the following:

// to send/publish an event to the topic
dojo.event.topic.publish("topicFoo", filterFoo);
// to listen/subscribe to all events published to a topic
dojo.event.topic.subscribe("topicFoo", this, "onFoo");

There is an additional example of this in the source tree at tests/event/test_topic.html. filterFoo in the example above is an object literal that is passed to onFoo.


disconnect and unsubscribe

To remove an event connection or a topic subscription, dojo.event.disconnect and dojo.event.topic.unsubscribe take exactly the same parameters as their counterparts.

event callbacks

People often ask questions like:

whenever buttonX is pressed, how do I call "saveHandler('x', evt)"?

This is a javascript closure question and is unrelated to dojo, but here's one way:

// createCallback() returns a function!
function createCallback(fieldId){
  // a new fieldId variable is created every time this function
  // is called, and it's saved by closure magic
  return function(evt){ saveHandler(fieldId, evt); } ;
}

var fieldId='x';
var callbackFunc = createCallback(fieldId);
dojo.event.connect(dojo.widget.byId(fieldId), "onSave", callbackFunc );

Event object

dojo.event.browser.fixEvent(/* event object or nothing for IE*/)

can normalize event objects so you can use common event code in any browser. dojo.event.connect uses fixEvent automatically, so connected functions always get a normalized event object as an argument. Fixed event objects have these modifications:

For key events, a set of event key code aliases are installed, so you can express (e.keyCode == e.KEY_ESC). Also, a reverse key code lookup is installed, so you can express (e.revKeys[e.keyCode] == 'KEY_ESC').

These properties/methods are made available in all browsers:

 target
 currentTarget
 pageX/pageY - position of cursor relative to viewport
 layerX/layerY
 fromElement
 toElement
 charCode
 stopPropagation() - stops other event handlers (on parent domnodes) from firing
 preventDefault() - stops things like following the href on a hyperlink.
 callListener() - ???

Additionally, event (W3) vs. window.event (IE) is taken care of: all connected event handlers get passed a fixed event object (even in IE).

posted on 2006-09-28 14:12 不做浮躁的人 阅读(778) 评论(0)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航:
 

<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

常用链接

留言簿(9)

随笔分类(31)

随笔档案(75)

文章分类(1)

文章档案(3)

搜索

  •  

最新评论

阅读排行榜

评论排行榜