继续学习Dojo的事件机制:
事件指派(Event Delegation)
NodeList 的on函数可以给一串DOM节点赋值handler事件处理函数。dojo/on也通过事件指派来实现这个功能
事件指派的意思:
不对每一个DOM元素都指定事件处理函数,而是给DOM树中尽量最高级别的元素上指定一个事件处理函数。按照事件冒泡原理,低级别的DOM元素的事件会传递到高级别DOM元素上。这个高级别的DOM元素会检查捕获到的事件,只要判断传递来的事件的属于哪个子元素,然后去做相应的子元素的处理。
事件指派的好处是:
1,减少事件处理程序的数量,提升页面的性能:每个函数都是对象,都会占用内存,所以事件处理程序的数量关系到整个页面的运行性能。
2,减少对DOM元素的访问次数:每个定义的事件处理程序都会绑定到DOM元素上,也就有对DOM元素的访问。减少事件处理程序的数量,一定程度上减少对DOM元素的访问。
适合事件指派的事件:
适合采用事件指派技术的事件包括click, mousedown, mousup, keydown, keyup, keypress。虽然mouseover和mouseout事件也冒泡,但是处理它们并不容易,而且经常需要计算它们的位置。
之前的dojo版本dojox/Nodelist/delegate 会实现这个事件委托,现在依然有用。1.10版本开始,也可以用dojo/on 模块来实现相关功能,使用on函数语法:
**on(parent element, "selector:event name",handler)**
例子如下:
<div id="parentDiv">
<button id="button1" class="clickMe">Click me</button>
<button id="button2" class="clickMe">Click me also</button>
<button id="button3" class="clickMe">Click me too</button>
<button id="button4" class="clickMe">Please click me</button>
</div>
<script>
require(["dojo/on", "dojo/dom", "dojo/query", "dojo/domReady!"],
function(on, dom){
var myObject = {
id: "myObject",
onClick: function(evt){
alert("The scope of this handler is " + this.id);
}
};
var div = dom.byId("parentDiv");
on(div, ".clickMe:click", myObject.onClick);
});
</script>
查看运行结果: 事件指派例子–运行结果
注意:1,使用中,仍然需要dojo/query模块,即使我们不会直接使用到模块功能。因为 dojo/on需要dojo/query的选择引擎去匹配dom元素而指派事件。
2,上述例子也能说明一个问题,事件指派设计中,事件处理关注并不是高级别元素(也可以称之为父级元素),虽然这个元素作为第一个参数传递到on中。事件指派的处理函数关注的是处理匹配的子元素的操作。
对象方法
dojo/on的“前任”dojo.connect, 负责方法到方法的事件链接。这个功能已经单独成一个模块:dojo/aspect.
Publish/Subscribe
之前的例子处理的情况是:已知一个对象以及已知其要做event处理。但是,如果在你不知道一个节点对象要处理什么event的时候(也许可以理这个理解:只知道这个节点要进行和某个已知对象的event操作一样,至于具体事件处理程序不知道),或者甚至不知道何时这个对象会被创建。这种情况下,你需要Dojo 的dojo/topic模块的publish与subscribe (pub/sub)。
这个框架是1.10开始引入。Pub/sub允许注册一个处理函数handler(通过subscribe) 到一个 topic,这个topic其实是事件别名的string形式。这个事件可以拥有多种资源,被多个节点使用。当这个topic被publish时handler会被调用。
pub/sub适用场景:
当你开发一个应用时,希望有个按钮去提现用户操作。我们不想重复开发,这个小功能又不值得包装成对象。
通过以下例子更深一步理解pub/sub
<button id="alertButton">Alert the user</button>
<button id="createAlert">Create another alert button</button>
<script> require(["dojo/on", "dojo/topic", "dojo/dom-construct", "dojo/dom", "dojo/domReady!"], function(on, topic, domConstruct, dom) { var alertButton = dom.byId("alertButton"), createAlert = dom.byId("createAlert"); on(alertButton, "click", function() { // When this button is clicked, // publish to the "alertUser" topic topic.publish("alertUser", "I am alerting you."); }); on(createAlert, "click", function(evt){ // Create another button var anotherButton = domConstruct.create("button", { innerHTML: "Another alert button" }, createAlert, "after"); // When the other button is clicked, // publish to the "alertUser" topic on(anotherButton, "click", function(evt){ topic.publish("alertUser", "I am also alerting you."); }); }); // Register the alerting routine with the "alertUser" topic. topic.subscribe("alertUser", function(text){ alert(text); }); }); </script>
查看运行结果:对象事件例子–运行结果
这种模式的事件写法使得事件处理与事件对象解耦,这样有一个优点:不需要创建DOM元素,就可以进行单元。若不想再保持一个主题,topic.subscribe返回一个对象,这个对象有一个remove方法,这个方法可以移除相应事件处理(与on函数类似)。
注意: 不同于dojo.publish,topic.publish参数不需要写成数组形式。以下两种写法是相等的,注意参数的不同写法:
topic.publish("someTopic", "foo", "bar")
dojo.publish("someTopic", ["foo", "bar"]).
Dojo事件总结
dojo事件机制很强大,也很容易使用。on方法屏蔽了浏览器之前的不一致。pub/sub框架中,dojo/topic给出了一种解绑事件处理程序与事件对象的方法。需要多花时间去熟悉这些工具,相信在web应用的构建中还是很有益处的。