Dojo 事件<10>

在这个教程里,我们将解释 dojo/on 以及如何使用它来监听DOM事件。 我们也会讲解 Dojo的 publish/subscribe框加: dojo/topic.

开始

许多Javascript 代码用于处理事件:响应一个件事或者产生一个新的事件。交互式web应用程序创建有效的事件连接,关键在于建立响应。事件连件允许你的应用响应用户的交互并且等待动作的发生。 Dojo的主要DOM事件处理器是通过dojo/on完成。 接下来让我告诉你如何使用这个模块!

DOM事件

你可能会问自己, “DOM是否已经提供了一个注册事件处理的机制?" ,文档对象模型本身是提供了事件处理,但不是所有的浏览器都遵循W3C的DOM规范。主流的三种处理事件方式: addEventListener,attachEvent,和 DOM 0. 除此以外,这里还有两种不同的事件对象实现 和至少一个在随机的顺序下触发监听事件和内存泄露的浏览器引擎。你只需简单的使用dojo/on模块就可以处理所有问题,不用考虑各种不同的原生API以及防止内存的工作。

让我们看看下面的HTML标记:
<button id="myButton">Click me!</button>
<div id="myDiv">Hover over me!</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,"red");
        });
        on(myDiv,mouse.leave,"");
        });
});

!* 注间 dojo/mouse资源是必须要的。 不是所有的浏览器都本地支持mouseenter和mouseleave 事件, 所以需要添加dojo/mouse. 可以自己像dojo/mouse一样创建自己的模块,以支持其它自定义事件类型。

这个例子说明了常见的模式: on(element,event name,handler). 或换句话说, 发现在这个元素的这个事件,连接到这个处理程序上。 这种模式可以应用到所有的窗口,文档, 节点,form, 鼠标, 和键盘事件上。

!* 注意,不像老的dojo.connect API,当使用dojo/on模块时, "on" 事件名称的前缀(onClick中的on)必须被省略。

on 方法不仅权能使用注册事件API正规化。它使用处理事件也正规化:

  • 事件的处理顺序是注册时的顺序。
  • 事件处理程序的第一个参数是一个事件对象。
  • 事件对象会被标准化为包含 W3C中事件对象的属性, 包含 target属性, stopPropagation方法以及preventDefault方法。
类似于DOM API,Dojo 也提供了移除事件监听器的方法: handle.remove. on方法返回的对象会用于remove方法。如果你想一个监听器只使用一次,可以如下所示:
var handle = on(myButton,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.");
});

!* 附带提一下, dojo/on 包含 一个更方像的方法:on.once. 它跟on法方一下,接受相同的参数。 但它将在一次触发后自动移除监听器。

最后需要注意的事项: 默认时, on 将会在第一个被传入的参数(节点)上下文里运行 事件处理函数。 除非on 使用了事件委托,之后会讨论什么是事件委托。

但是,你可以使用lang.hitch(dojo/_base/lang模块)来指名事件处理程序的运行上下文。 勾子在对象方法里非常有用。

require(["dojo/on","dojo/_base/lang",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,myObject.onClick);
        // This will alert "myObject" rather than "myScopedButton2"
        on(myScopedButton2,lang.hitch(myObject,"onClick"));
 
});

查看示例

!* 不像on 的前任, dojo.connect. on 不在接受监听器的作用和方法参数。 如果你想要保留执行上下文,你需要在第三个参数中使用lang.hitch.

节点列表事件

在上个教程(dojo/query)提到过的, NodeList 提供了给多个节点注册事件的方法 - on 方法。 这个方法除了第一个参数跟dojo/on不一样外,其它的都是一样。

!* dojo/query 包含了 on方法, 所以你不需要在加载dojo/on模块来使用NodeList.on。

让我们看看比上一个更高级的例子
<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",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","onClick"));
 
});
</script>
!* 注意,不像NodeList.connect,NodeList.on方法不会为了链式调用而返回NodeList对象。 代替的是它返回一个监听器数组,之后可以被移除。 这个数组包含一个数组级的remove方法(相对于遍历每个元素,在remove) 它可以一次移除所有的监听器。


事件委托

如上面的讨论, NodeList的on方法可以给多个DOM节点的相同事件连接相同的处理函数。 dojo/on也可以通过更加有效的事件委托机制,完成相同的任务。

事件委托的原理是把原先给每个自己感兴趣的节点注册监听器,改为给它们的更高一级的节点注册一个监听器。 之后可以检查它捕获的事件,是否是你感觉的实际节点触发(冒泡到父节点)。 如果是, 监听器的代码会被执行。

以前,它是(现在依然是)通过dojox/NodeList/delegate扩展到NodeList. 在1.9,它也可以dojo/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/query",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>

!*注意, 我们虽然没有直接使用到dojo/query 模块,但也加载了它, 这是因为dojo/on为了事件委托中能够使用选择器,所以需要用到dojo/query的选择器引擎。 dojo/on不会自动加载dojo/query,是为了开发者在不需要这个功能时,不需额外加载dojo/query模块。


当运行上面的 Demo,注意到 this 依然会引用实际的节点,而不是parentDiv(父节点)。 当为事件委托使用on 和一般注册监听器使用on,有一个最要的区别: this 不在引用第一个被传入的参数的节点, 而是 选择器匹配到的节点。

对象方法(面向方面编程)

dojo/on的前任, dojo.connect,可以处理函数到函数的事件连接。 这个功能已经单独到 dojo/aspect。 期待不久出的dojo/aspect教程

发布与订阅

到目前为此,上面的例子都是给已知的对象(节点)注册已知的事件。 但是如果你不知道给节点注册什么事件或者 事件源对像还没有创建时,该怎么做? 这里需要使用到Dojo的 publish 和 subscribe(pub/sub)框架, 1.9采用dojo/topic模块。 Pub/sub允许你给一个"topic" (设想的一个事件,可以有多个事件源,为一个字符串)注册一个监听器。 这个监听器会在topic被发布时调用。

让我们想下一个正在开发的应用, 我们想某个按纽提示用户的一个行为。 我们不想一次又一次的写提示这个功能, 但我们又不想给 button注册一个包装对象(定义一个对象,如上面的例子)。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",topic,domConstruct,dom) {
 
        var alertButton = dom.byId("alertButton"),createAlert = dom.byId("createAlert");
 
        on(alertButton,function() {
            // When this button is clicked,// publish to the "alertUser" topic
            topic.publish("alertUser","I am alerting you.");
        });
 
        on(createAlert,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,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>

查看 Demo

使用这种事件模式的优势在于, 我们的应用程序在单元测试时可以不需要创建DOM 对象。 例行程序(监听器的代码) 可以跟 事件的生产者解偶。

如果你不在想接收到一个topic的通知, topic.subscribe会返回一个对象, 这个对像中的remove方法可以删除掉监听器。(如同dojo/on).

!* 注意不像dojo.publish,topic publish 不在接受一个数组。 例如 topic.publish("someTopic","foo","bar") 等于 dojo.publish("someTopic",["foo","bar"]).

总结

Dojo的事件系统非常强大, 而使用时又非常简单。 on方法正常化了DOM事件在浏览器的不同。 Dojo的 pub/sub框架, dojo/topic, 为开发者提供了对事件处理和事件源更好的解偶提供了方法。 花更多的时间来了解这些工具,有利于创建更好的web应用程序。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


我有一个网格,可以根据更大的树结构编辑小块数据.为了更容易知道用户保存了什么,我希望当用户第一次看到网格时,网格处于不可编辑状态.当用户准备好后,他们可以单击编辑按钮,这将使网格的某些部分可编辑.然后,有一个保存或取消按钮可以保存更改或还原.在大多数情况下它是有效的.但
我即将开始开发一款教育性的视频游戏.我已经决定以一种我可以轻松打包为Web,Mobiles和可能的Standalone版本的方式来实现这一目标.我不想使用Flash.因此,我确信(无论如何我会听取建议)使用JavaScript和SVG.我正在对这个问题进行大量研究,但我很难把各个部分放在一起.我知道Raphae
我正在使用带有Grails2.3.9的Dojo1.9.DojoNumberTextBox小部件–我在表单中使用–将固定格式(JavaScript基本格式)的实数值(例如:12.56)设置为HTML表单输入字段(但根据浏览器区域设置显示/编辑它们,所以用户总是看到格式正确的数字).另一方面,Grails期望输入字段根据浏览器
1.引言鉴于个人需求的转变,本系列将记录自学arcgisapiforjavaScript的学习历程,本篇将从最开始的arcgisapiforjavaScript部署开始,个人声明:博文不在传道受业解惑,旨在方便日后复习查阅。由于是自学,文章中可能会出现一些纰漏,请留言指出,不必留有情面哦!2.下载ArcGISforDe
我正在阅读使用dojo’sdeclare进行类创建的语法.描述令人困惑:Thedeclarefunctionisdefinedinthedojo/_base/declaremodule.declareacceptsthreearguments:className,superClass,andproperties.ClassNameTheclassNameargumentrepresentsthenameofthec
我的团队由更多的java人员和JavaScript经验丰富组成.我知道这个问题曾多次被问到,但为了弄清楚我的事实,我需要澄清一些事情,因为我在客户端技术方面的经验非常有限.我们决定使用GWT而不是纯JavaScript框架构建我们的解决方案(假设有更多的Java经验).这些是支持我的决定的事实.>
路由dojo/framework/srcouting/README.mdcommitb682b06ace25eea86d190e56dd81042565b35ed1Dojo应用程序的路由路由FeaturesRoute配置路径参数RouterHistoryManagersHashHistoryStateHistoryMemoryHistoryOutletEventRouterContextInjectionOutl
请原谅我的无知,因为我对jquery并不熟悉.是否有dojo.connect()的等价物?我找到了这个解决方案:http:/hink-robot.com/2009/06/hitch-object-oriented-event-handlers-with-jquery/但是没有断开功能!你知道jquery的其他解决方案吗?有jquery.connect但这个插件在我的测试中不起作用.
与java类一样,在dojo里也可以定义constructor 构造函数,在创建一个实例时可以对需要的属性进行初始化。//定义一个类mqsy_yjvar mqsy_yj=declare(null,{     //thedefaultusername    username: "yanjun",          //theconstructor   
我一直在寻找一些最佳实践,并想知道Dojo是否具有框架特定的最佳实践,还是最好只使用通用的Javascript标准?特别是我主要是寻找一些功能和类评论的指导方针?解决方法:对于初学者来说,这是项目的风格指南:DojoStyleGuide
我有’05/17/2010’的价值我想通过使用dojo.date.locale将其作为“2010年5月17日”.我尝试过使用dojo.date.locale.parse,如下所示:x='05/17/2010'varx=dojo.date.locale.parse(x,{datePattern:"MM/dd/yyyy",selector:"date"});alert(x)这并没有给我所需的日期
我正在尝试创建一个包含函数的dojo类,这些函数又调用此类中的其他函数,如下所示:dojo.provide("my.drawing");dojo.declare("my.drawing",null,{constructor:function(/*Object*/args){dojo.safeMixin(this,args);this.container=args[0];
我知道你可以使用jQuery.noConflict为jQuery做这件事.有没有办法与Dojo做类似的事情?解决方法:我相信你可以.有关在页面上运行多个版本的Dojo,请参阅thispage.它很繁琐,但似乎是你正在寻找的东西.一般来说,Dojo和jQuery都非常小心,不会破坏彼此或其他任何人的变量名.
我有一个EnhancedGrid,用户经常使用复杂的过滤器.有没有办法允许用户保存或标记过滤器,以便将来可以轻松地重新应用它?我知道我可以通过编程方式设置过滤器,但我无法预测用户想要的过滤器.谢谢!编辑:自己做了一些进展…使用grid.getFilter()返回过滤器的JSON表示,然后使用json.strin
我有这个代码:dojo.declare("City",null,{constructor:function(cityid,cityinfo){}});dojo.declare("TPolyline",GPolyline,{constructor:function(points,color){},initialize:function(map){});应该是什
我遇到的问题是我的所有javascript错误似乎来自dojo.xd.js或子模块.我正在使用chrome调试器和许多dijit功能,如dijit.declaration和dojo.parser.这有点烦人,因为它很难找到简单的错误或滑倒.我希望我可以添加一个选项,允许我的调试器在我的非dojo代码中显示选项会发生的位置.我是
我正在使用DojoToolkit数字/解析函数来处理格式化和使用ICU模式语法解析字符串.有没有人知道有可能采取任意ICU模式字符串并以某种方式使用Dojo(或其他)库将其分解为它的部分(例如,对于数字模式,它可以被分解为小数位数,数千个分组等…).我希望这样做,而不需要让我的代码密切了
我有两个看似相关的问题,访问在不同的地方定义的javascript函数.我遇到的第一个问题是调用我在firgbug或safari控制台中定义的函数.我定义了一个名为getRed的函数,如下所示:functiongetRed(row,col){//dosomethingstuffandreturntheredvalueasa
我想添加一个在Ajax调用中指定的外部样式表.我已经找到了一种方法来使用jQuery(参见下面的示例),但是我需要使该方法适应dojoJavaScript框架.JQuery示例$('head').append('<linkrel="stylesheet"type="text/css"href="lightbox_stylesheet.css">');谢谢.解决方法:一旦你
我正在尝试使用dojo.connect将onMouseDown事件连接到图像,如:dojo.connect(dojo.byId("workpic"),"onMouseDown",workpicDown);functionworkpicDown(){alert("mousedown");}类似的代码几行后,我将onMouse*事件连接到dojo.body确实完全正常工作.但是当我点击图像时