Events with Dojo(翻译)
In this tutorial, we will be exploring dojo/on
and how Dojo makes it easy to connect to DOM events. We will also explore Dojo's publish/subscribe framework: dojo/topic
.
在本教程中,我们将会探讨dojo/on模块,使用该模块可以更简单的关联DOM事件。我们也会探讨dojo的publish和dubcribe框架:dojo/topic。
Getting Started 开始
Much of your JavaScript code will be preparing for events: both responding to and generating new events. This means that the key to building responsive, interactive web applications is creating effective event connections. Event connections allow your application to respond to user interaction and wait for actions to happen. Dojo's main DOM event workhorse is dojo/on
; let me show you how to use this module!
在很多javascript代码中,我们编写响应事件和创建新事件的代码。这就意味着,能够创建有效的事件连接机制,是我们创建一个交互响应丰富的Web应用的重要前提。事件可以让你的web应用和用户操作关联在一起,让你的事件响应代码或函数一直等待着事件被触发。在dojo中,定义事件相关功能的模块是dojo/on模块,下面我们看下如何使用该模块。
DOM Events DOM事件
You might be asking yourself, “Doesn’t the DOM already provide a mechanism for registering event handlers?” The answer is yes—but not all browsers follow the W3C DOM specification. Between the various DOM implementations from major browser vendors there are three ways to register event handlers: addEventListener
, attachEvent
, and DOM 0. Beyond that, there are two different event object implementations and at least one browser engine that fires registered listeners in random order.aspx) and leaks memory.aspx). Dojo improves the way you work with DOM events by normalizing differences between the various native APIs, preventing memory leaks, and doing it all in a single, straightforward event API called dojo/on
.
Let’s say we have the following markup:
你可能会忍不住问,DOM本身没有提供原生态的事件响应机制吗? 是的,DOM提供了,但并不是所有的浏览器都是基于W3C标准设计的,而DOM提供的事件只支持W3C标准下的浏览器。在各种版本的DOM标准和各种浏览器中,注册事件有三种方式:addEventListener
, attachEvent
, and DOM 0。在此之前,有两个不同的事件实现对象和至少一个浏览器引擎。dojo则提供了一种标准的事件操作API,是用该方式,你可以忽略各种不同版本API的差异,防止内存泄漏等。所以你只要了解dojo/on模块提供的一种API就可以解决以前遇到的诸多问题。
Let’s say we have the following markup:
让我们看下下面的例子:
<button id="myButton">Click me!</button>
<div id="myDiv">Hover over me!</div>
Let's also imagine that you want the div
to change to blue when you click the button, red when you hover over it, and back to white when you're done hovering. dojo/on
makes that very simple:
当鼠标点击按钮的时候,我们想把div的颜色变成蓝色,当鼠标移动到div的时候,把它的颜色变为红色,当鼠标离开的时候,又变回白色。使用dojo/on模块实现该功能是很简单的。
require(["dojo/on", "dojo/dom", "dojo/dom-style", "dojo/mouse", "dojo/domReady!"],
function(on, dom, domStyle, mouse) {
var myButton = dom.byId("myButton"),
myDiv = dom.byId("myDiv"); on(myButton, "click", function(evt){
domStyle.set(myDiv, "backgroundColor", "blue");
});
on(myDiv, mouse.enter, function(evt){
domStyle.set(myDiv, "backgroundColor", "red");
});
on(myDiv, mouse.leave, function(evt){
domStyle.set(myDiv, "backgroundColor", "");
});
});
Notice that the
dojo/mouse
resource was also required. Not all browsers natively supportmouseenter
andmouseleave
events, sodojo/mouse
adds that support. You can write your own modules likedojo/mouse
to enable support for other custom event types.需要注意的是,我们需要加载dojo/mouse资源模块。并不是所有的浏览器都原生态支持mouseenter和mouseleave时间,所以,dojo/mouse做了一些操作,使这些浏览器也支持。你也可以写一个类似于dojo/mouse的自定义模块去支持其他的自定义事件。
This example illustrates the common pattern: on(
element,
event name,
handler)
. Or, put another way, for this event on this element, connect this handler. This pattern applies to all window, document, node, form, mouse, and keyboard events.
该例子通过举例说明了on(element,event name,hanslder)函数的用法。用另外一种方式描述就是为一个元素的时间关联了一个函数。在处理window、document、node、form、mouse、和keyboard事件时也是使用的这种模式。
Note that unlike the older
dojo.connect
API, the "on" event name prefix must be omitted when using thedojo/on
module.注意,不同于之前旧的dojo.connectAPI,在引用dojo/on模块之后,on前面的dojo前缀是可以省略掉的。
The on
method not only normalizes the API to register events, but it also normalizes how event handlers work:
on函数不仅规范化了注册事件的API,而且还规范了事件引用的工作机制:
- Event handlers are always called in the order they are registered.
- They are always called with an event object as their first parameter.
- The event object will always be normalized to include common W3C event object properties, including things like a
target
property, astopPropagation
method, and apreventDefault
method. - 注册到事件上的处理函数在执行时,执行的顺序和其注册的顺序是一致的。
- 注册到事件上的处理函数的第一个参数是事件对象参数。
- 事件对象是支持W3C标准规范的,其对象包括target属性、
stopPropagation
函数和preventDefault
函数。
Much like the DOM API, Dojo also provides a way to remove an event handler: _handle_.remove
. The return value of on
is a simple object with a remove
method, which will remove the event listener when called. For example, if you wanted to have a one-time only event, you could do something like this:
和DOM原生态API一样,dojo也提供了移除一个事件委托函数的方法:_handle_.remove。on函数返回的是一个简答对象,该对象包含了一个remove函数,当我们想移除该事件监听的时候,调用该函数即可。例如,如果你想让事件只执行一次,那么你可以写下面的代码:
var handle = on(myButton, "click", function(evt){
// Remove this event using the handle
handle.remove(); // Do other stuff here that you only want to happen one time
alert("This alert will only happen one time.");
});
Incidentally,
dojo/on
includes a convenience method for doing exactly this:on.once
. It accepts the same parameters ason
, but will automatically remove the handler once it is fired.事实上,dijo/on模块包含了一个更简单的方法:on.once。该函数的参数和on函数一样,但该事件被触发一次之后,事件委托句柄就会被移除掉。
One last thing to note: by default, on
will run event handlers in the context of the node passed in the first argument. The one exception to this is when on
is used for event delegation, which we will discuss shortly.
最后需要注意的是:默认情况下,on函数会吧返回的事件句柄作为事件函数的第一个参数传到函数中。一个例外的情况,就是on作为事件委托使用,这点我们会稍后讨论。
However, you can use lang.hitch
(from the dojo/_base/lang
module) to specify the context in which to run the handler. Hitching is very helpful when working with object methods:
我们可以使用lang.hitch(定义在dojo/_base/lang模块)指定运行事件委托函数的上下文环境。当在对象的函数基础上运行时,Hitching是非常有用的:
require(["dojo/on", "dojo/dom", "dojo/_base/lang", "dojo/domReady!"],
function(on, dom, lang) { var myScopedButton1 = dom.byId("myScopedButton1"),
myScopedButton2 = dom.byId("myScopedButton2"),
myObject = {
id: "myObject",
onClick: function(evt){
alert("The scope of this handler is " + this.id);
}
}; // This will alert "myScopedButton1"
on(myScopedButton1, "click", myObject.onClick);
// This will alert "myObject" rather than "myScopedButton2"
on(myScopedButton2, "click", lang.hitch(myObject, "onClick")); });
Unlike on
's predecessor, dojo.connect
, on
does not accept the handler scope and method arguments. You will need to make use of lang.hitch
for the third argument if you wish to preserve execution context.
不同于on的前身dojo/connection,on模块不接受事件委托函数范围以及函数参数。你可以使用lang.hitch作为第三个参数,为当前运行的代码提供上下文环境。
NodeList events 节点列表事件
As mentioned in the previous tutorial, NodeList
provides a way to register events to multiple nodes: the on
method. This method follows the same pattern as dojo/on
without the first argument (since the nodes in the NodeList
are the objects you are connecting to).
正如我们在前面教程阐述的,NodeList提供了on函数,用来为节点批量注册事件。和dojo/on模块中的on函数相比,除了不需要第一个参数之外,其他的实现机制都是一样的。
The
on
method is included withdojo/query
, so you do not have to require thedojo/on
resource explicitly to useNodeList.on
.NodeList的on函数定义在dojo/query模块中,所以你在使用NodeList的on函数时,不需要在加载dojo/on模块。
Let's look at a more advanced example than before:
让我们再看下比之前的稍复杂些的例子:
<button id="button1" class="clickMe">Click me</button>
<button id="button2" class="clickMeAlso">Click me also</button>
<button id="button3" class="clickMe">Click me too</button>
<button id="button4" class="clickMeAlso">Please click me</button>
<script>
require(["dojo/query", "dojo/_base/lang", "dojo/domReady!"],
function(query, lang) { var myObject = {
id: "myObject",
onClick: function(evt){
alert("The scope of this handler is " + this.id);
}
};
query(".clickMe").on("click", myObject.onClick);
query(".clickMeAlso").on("click", lang.hitch(myObject, "onClick")); });
</script>
Note that unlike
NodeList.connect
, theNodeList.on
method does not return the NodeList back for further chaining; instead, it returns an array ofon
handles that can beremove
d later. The array also includes a convenient top-levelremove
method, which will remove all of the listeners at once.注意,不同于NodeList.connect,NodeList.on函数不在返回NodeList,而是返回一组事件委托对象集合,这些集合可以在后面的代码中被移除掉。这个集合也包含了remove函数,可以一次把所有事件监听一次全部移除。
Event Delegation 事件委托
As discussed above, the on
method of NodeList
makes it easy to hook up the same handler to the same event of multiple DOM nodes. dojo/on
also makes this achievable through a more efficient means known as event delegation.
正如我们在上面讨论的,NodeList的on函数可以很方便的为多个DOM节点设置同样的事件响应函数引用。当我们得到一个事件委托的时候,使用dojo/on模块,也可以很快速的达到该目的。
The idea behind event delegation is that instead of attaching a listener to an event on each individual node of interest, you attach a single listener to a node at a higher level, which will check the target of events it catches to see whether they bubbled from an actual node of interest; if so, the handler's logic will be performed.
事件委托出现的目的是为了不让每个要响应事件的节点都添加监听。
Previously, this was (and still is) achievable through the dojox/NodeList/delegate
extension to NodeList
. In 1.10, it is also possible using the dojo/on
module, using the syntax on(
parent element, "
selector:
event name",
handler)
.
To better illustrate this, let's look at another example, based on the same premise as the previous one:
<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>
Notice that we also required the
dojo/query
module, although we don't use it directly. This is becausedojo/on
needs a selector engine exposed bydojo/query
in order to be able to match selectors used for event delegation. This is not pulled in automatically bydojo/on
in order to reduce its footprint and avoid "penalizing" developers for a feature that might not always be used.需要注意的时,虽然我们没有直接引用dojo/query模块,但我们依然加载了它。主要是因为我们在dojo/on模块中使用到了dojo/query模块提供的筛选函数,以通过选择器匹配事件委托器。主要是该方法可能开发者不是经常使用,为了避免脚本下载的大小影响效率,dojo/on没有做dojo/query显示依赖,所以需要手动的加载一下。
When running the above demo, notice how this
still refers to the actual node we are interested in, not the parentDiv
node. This is an important distinction to note when using on
for event delegation: this
no longer refers to the node passed as the first argument, but rather to the node which the selector matched. This can actually be quite useful, once you know to expect it.
当我们运行上面的例子时,注意到,为什么this这个引用依然指向我们感兴趣的Button,而不是div节点?在使用事件委托和on函数时和直接使用事件注册一个很重要的区别:this已经不再指向函数的第一个参数,而是指向选择器匹配的节点。这点在实际开发时非常有用。
Object Methods
dojo/on
's predecessor, dojo.connect
, was also responsible for function-to-function event connections. This functionality has been broken out into its own resource called dojo/aspect
. Look forward to seeing a dojo/aspect
tutorial very soon!
dojo.connect,作为dojo/on模块的前任,依然可以负责通过函数对函数进行事件连接。这些功能被分散到了dojo/aspect模块中,我们将很快会看到该教程。
Publish/Subscribe 发布/订阅
All of the examples up until this point have used an existing object as an event producer that you register with to know when something happens. But what do you do if you don't have a handle to a node or don't know if an object has been created? This is where Dojo's publish and subscribe (pub/sub) framework comes in, exposed via the dojo/topic
module in 1.10. Pub/sub allows you to register a handler for (subscribe to) a "topic" (which is a fancy name for an event that can have multiple sources, represented as a string) which will be called when the topic is published to.
到目前为止,所有的例子都是你已经存在了一个对象,该对象有一些事件,你定义了一些函数注册到该事件上。但如果你没有一个节点的引用,或者你不知道一个对象是否被创建怎么办?这就是dojo订阅和发布框架出现的原因,该框架定义在dojo1.10的dojo/topic模块中。
Let's imagine that in an application that we're developing, we want certain buttons to alert the user of an action; we don't want to write the routine to do the alerting more than once, but we also don't want to make a wrapping object that will register this small routine with the button. Pub/sub can be used for this:
<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>
One useful advantage to this pattern of events is that now our alerting routine can be tested in a unit test without the need to create any DOM objects: the routine is decoupled from the event producer.
If you ever wish to stop receiving notifications of a topic, topic.subscribe
returns an object with a remove
method that can be used to remove the respective handler (much like on
).
Note that unlike
dojo.publish
,topic.publish
does not expect published arguments to be passed in an array. For instance,topic.publish("someTopic", "foo", "bar")
is equivalent todojo.publish("someTopic", ["foo", "bar"])
.
Conclusion
Dojo's event system is quite powerful, while being fairly simple to use. The on
method normalizes DOM event inconsistencies between browsers. Dojo's pub/sub framework, dojo/topic
, gives developers a way to easily decouple event handlers from the event producers. Take time to familiarize yourself with these tools — they will be a valuable asset in creating web applications.
Events with Dojo(翻译)的更多相关文章
- Hello Dojo!(翻译)
http://dojotoolkit.org/documentation/tutorials/1.10/hello_dojo/index.html 欢迎学习DOJO!在本教程中,你将学些到如何加载DO ...
- Using dojo/query(翻译)
In this tutorial, we will learn about DOM querying and how the dojo/query module allows you to easil ...
- ExtJS笔记 Using Events
Using Events The Components and Classes of Ext JS fire a broad range of events at various points in ...
- DOJO 八 event dojo/on
官网教程:Events with Dojo在元素上绑定events,需要引用包dojo/on,通过on方法来实现. <button id="myButton">Clic ...
- ASP.NET 生命周期(原文翻译)
在网上看到这篇文章,老外写的,里面很多图片挺精致,顺带翻译过来给大家分享下,英语太次好多地方都翻不过来 ASP.NET application and page life cycle Download ...
- [转]dojo/mouse
dojo/mouse Authors:Kris Zyp Project owner:Kris Zyp since:1.7.0 Contents Usage enter leave mouseButto ...
- 多级字典表单的Python实现
需求: 可依次选择进入各子菜单 可从任意一层往回退到上一层 可从任意一层退出程序 数据结构 menu = { '北京':{ '海淀':{ '五道口':{ 'soho':{}, '网易':{}, 'go ...
- Monkey原理初步和改良优化--Android自动化测试学习历程
章节:自动化基础篇——Monkey原理初步和改良优化(第三讲) 主要讲解内容与笔记: 一.理论知识: 直接看文档,来了解monkey的概念.基本原理,以及如何使用. First,what is And ...
- Caliburn.Micro 杰的入门教程4,事件聚合器
Caliburn.Micro 杰的入门教程1(原创翻译)Caliburn.Micro 杰的入门教程2 ,了解Data Binding 和 Events(原创翻译)Caliburn.Micro 杰的入门 ...
随机推荐
- 兼容解决 IE 、火狐、谷歌浏览器中 Iframe框架的页面缓存的方法
<script type="text/javascript"> document.write('<iframe src="/ad_footer.html ...
- 关于Windows7的安装纠结过程
关于Windows7的安装过程 背景交代 因为自己有两个笔记本,一个是伴我读过四年大学生活的老华硕笔记本,一个是姐夫不用的上网本.自己的构想是将老笔记本装上Ubuntu Server当作平时开发pyt ...
- 让LinqToSQL使用Web.Config中的链接字符串(修改Settings.Designer.cs)
[global::System.Configuration.ApplicationScopedSettingAttribute()] [global::System.Diagnostics.Debug ...
- Android中proc/meminfo的详解(原)
今天在写到获取手机可用内存空间的总大小的时候,通过下面的方法去获取的时候,发现该方法最低支持的版本是16,这显然是不可取的. public static long getTotalSpace(Cont ...
- MySQL 性能调优之查询优化
见原文: http://www.cnblogs.com/markjiao/p/5665775.html
- textarea关于空格和换行那点事
textarea中空格连续输入多个的情况下,数据回显的时候页面只是显示一个:换行同样有问题,在textarea中有换行,在页面上却没有,今天终于看到个写的比较具体的文章,拿过来收藏下. 地址链接: h ...
- CoreData数据库
一 CoreData 了解 1 CoreData 数据持久化框架是 Cocoa API 的一部分,首先在iOSS5 版本的系统中出现: 它允许按照 实体-属性-值 模式组织数据: ...
- Convert.ToInt32()与int.Parse()的区别
Convert.ToInt32()与int.Parse()的区别 (1)这两个方法的最大不同是它们对null值的处理方法: Convert.ToInt32(null)会返回0而不会产生任何异常, ...
- CE 内存申请
char ch_ReadByte='H'; char *ptr_OneLineData; unsigned ); if ((ptr_OneLineData = (char *)malloc(bufsi ...
- JAVA的单例模式与延时加载
延迟加载(lazy load)是(也称为懒加载),也叫延迟实例化,延迟初始化等,主要表达的思想就是:把对象的创建延迟到使用的时候创建,而不是对象实例化的时候创建.延迟加载机制是为了避免一些无谓的性能开 ...