web前端之精通dojo五:利用Dojo进行DOM事件编程

原创 2017年01月02日 13:28:32

web前端之精通dojo五:利用Dojo进行DOM事件编程

如果针对浏览器编程,让它动态地做任何事,就必须将代码与DOM事件关联起来。这时你会发现有两种不同的事件API可用。不干预下风的IE提供了第三种API————同时还附送了内存泄漏问题。通过深入学习这些API,可以了解浏览器间的不兼容性以及各浏览器的特性。事件编程很快就成为了让人头疼的问题。

好在,Dojo为我们提供了一个完备的事件编程框架来解决这些问题。但是事件并不是Dojo异步编程的全部,而只是异步编程模型的一部分。Dojo还包括了一些使用这些模型的函数族,利用这些函数可以创建各种类型的有趣而强大的应用程序。

利用Dojo进行DOM事件编程

Dojo提供了一个DOM事件框架,该框架在所有Dojo支持的浏览器中具有一致的行为。Dojo更是修复了IE免费提供的内存泄漏问题。

下面概述一下事件驱动编程模型。事件发生时,将调用一个函数————称为处理函数。时间有时被称为信号,可能是一个硬件事件,例如鼠标手势;或是一个软件事件,例如提交表单。处理函数又被称为监听器或回调函数,是一个拥有明确定义的参数集合并在明确定义的上下文中执行的函数。

处理函数签名

处理函数也是函数,Dojo事件框架为处理函数提供了单一的参数,称为事件对象。该对象包含一些属性和方法,这些属性和方法按照W3C事件模型的规定描述和控制事件————这对于没有本地实现这一模型的IE也是一样的。如果你要编写一个不需要事件对象的处理函数,只需要声明一个不带参数的函数。由于要记录事件对象的信息,因此我们的处理函数要接受事件对象作为唯一的参数。

function handleClick(eventObj){
    console.log(
        "Event("+eventObj.type+") on Dom node "+eventObj.target.id+";currentTarget= "+eventObj.currentTarget.id
    );
}

有三种类型的事件对象构成一个继承单链:MouseEvent继承自UIEvent,UIEvent继承自Event.
这里写图片描述

要注意我们的处理函数没有返回值。处理函数都不需要返回值,因为它的任何返回值都将被忽略。

事件传播

对于有些事件,浏览器会把一个事件分派到多个DOM节点,这一过程称为事件传播。处理函数可以影响事件的传播,理解事件传播对于优化处理函数代码非常重要。

一般点击事件的过程是,当用户点击一个DOM节点时,一个点击事件被发送到目标节点(目标节点就是事件发生的节点)、它的父节点、祖父节点等等。一直到文档树的最上层。这个发送的过程叫做冒泡。

冒泡使我们可以将代码统一放到父节点。例如,假设我们有一个div节点,它含有100个子节点,每个子节点在结构上都是一致的并都使用同一个点击事件处理函数。我们可以为每一个子节点都关联这个处理函数,也可以只为它们的父节点div关联这个处理函数。父节点所关联的处理函数要检查事件对象的target属性,以此确定实际被点击的子节点。这个解决方法显然更胜一筹。

function someHandler(eventObj){
    /*.....*/
    eventObj.stopPropagation();
}

有时候你可能想阻止冒泡行为。例如,树结构中的一个底层节点的处理函数调用了它祖父节点的处理函数来处理一下事件,那么我们肯定不希望祖父节点的处理函数因为冒泡行为再次被调用。

关于冒泡和捕获等:查看详情

(1)捕获阶段
(2)调用目标节点的处理函数
(3)冒泡阶段

我们可以在事件处理过程中的任何地点利用任何处理函数阻止事件传播,只需要调用事件对象的stopPropagation方法。同样我们也可以跳过捕获阶段而不影响后面的两个阶段,这也正是Dojo事件框架的工作方式。这是一件非常好的事。当你思考之后救火发现捕获行为往往是错误的,捕获意味着通用的处理方式。

我们要增强点击处理函数,使它在按下shift键时不会冒泡:

function handleClick(eventObj){
    console.log(
        "Event("+eventObj.type+") on Dom node "+eventObj.target.id+";currentTarget= "+eventObj.currentTarget.id
    );
}
//eventObj的类型为MouseEvent
if(eventObj.shiftKey){
    // 在按下shift键时点击将阻止冒泡
    eventObj.stopPropagation();
}

随后我们就将这个处理函数与一个小型DOM树中的所有节点关联。这个示例会先显示冒泡行为(当点击时),然后会立刻阻止冒泡行为(当按下shift点击)

默认处理

无论是否有处理函数与之关联,每一个DOM事件都会引发浏览器执行一些默认处理行为。事件处理函数可以通过调用事件对象的preventDefault方法取消默认行为:

function someHandler(eventObj){
    eventObj.preventDefault();
}

最后介绍一下十分好用的函数dojo.stopEvent(event),它同时调用event.preventDefault()和event.stopPropagation()这两个函数

function someHandler(eventObj){
    /*...*/
    dojo.stopEvent(eventObejct);
    //完全等价于
    eventObj.stopPropagation();
    eventObj.preventDefault();
}

关联处理函数

Dojo提供了一个用来关联函数和DOM事件的dojo.connect方法。这个函数是Dojo事件框架的关键,因为它使事件处理函数按我们所描述的那样去执行,而且不依赖任何特定的浏览器。他的签名如下:

handle=dojo.connect(obj,event,context,handler);

从本质上讲,调用dojo.connect关联一个处理函数到一个DOM节点事件,就如同调用W3C DOM的obj.addEventListener(event,dojo.hitch(context,handler))。而且,即使当前浏览器不直接支持addEventListener的IE版本,Dojo也能做到同样的事情。

dojo.connect(obj,event,context,handler)的前面两个参数obj(一个DOM节点)和event(一个字符串)定义了要关联的事件。接下来的两个参数,context(可选,是一个对象)和handler(一个函数或者是字符串),定义了处理函数。这里context参数是语法糖衣,它是我们通过绑定函数到上下文(例如,绑定一个方法到一个对象)得到一个处理函数时,不需要显示调用dojo.hitch。我们将会看到这一模式在Dojo被频繁地使用。如果dojo.hitch让你一头雾水,就看前一篇博客。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>关联处理函数</title>
<script type="text/javascript" src="../../../dojoroot/dojo/dojo.js" djConfig="parseOnLoad:true"></script>
<script type="text/javascript">
function handleClick(eventObj){
    console.log(
        "Event("+eventObj.type+") on Dom node "+eventObj.target.id+";currentTarget= "+eventObj.currentTarget.id
    );
}
function connectAll(){
    dojo.connect(dojo.byId("body"),"click",handleClick);
    dojo.connect(dojo.byId("body-div"),"click",handleClick);
    dojo.connect(dojo.byId("body-div-p"),"click",handleClick);
    dojo.connect(dojo.byId("body-div-ol"),"click",handleClick);
    dojo.connect(dojo.byId("body-div-ol-li-1"),"click",handleClick);
    dojo.connect(dojo.byId("body-div-ol-li-2"),"click",handleClick);
    dojo.connect(dojo.byId("body-div-ol-li-3"),"click",handleClick);
    dojo.connect(dojo.byId("body-div-ol-li-4"),"click",handleClick);
    dojo.connect(dojo.byId("body-div-ol-li-5"),"click",handleClick);
    //上面的代码可以替换成
    //dojo.query("body *").connect("click",handleClick);
    //后续会讲到
}
function myClick1(event){
}
function myClick2(event){
}
dojo.connect(someDomNode,"click",function(event){
    myClick1(event),myClick2(event);
});
</script>
</head>
<body id="body">
    <div id="body-div">
        <p id="body-div-p">
            是理解事件的时候了
        </p>
        <ol id="body-div-ol">
            <li id="doby-div-ol-li-1">
                利用dojo.connect/disconnect链接/取消链接处理函数
            </li>
            <li id="doby-div-ol-li-2">
                总是向处理函数传递一个事情对象作为参数
            </li>
            <li id="doby-div-ol-li-3">
                不要用“this”引用当前目标
            </li>
            <li id="doby-div-ol-li-4">
                能冒泡的事件总是冒泡
            </li>
            <li id="doby-div-ol-li-5">
                完整的定义了键盘事件和相关的事件对象
            </li>
        </ol>
    </div>
</body>
</html>

利用connect可以将多个不同的处理函数关联到相同的(node,event)事件。这种情况下,处理函数的调用顺序不确定。

这样我们就可以把创建的处理函数与事件关联。

利用dojo.addOnLoad执行初始化代码

当我们调用dojo.connect把处理函数链接到Dom节点时,最好确保DOM树已经由浏览器创建,而且处理函数引用的所有其他JavaScript代码都已被下载并求值。我们需要确保dojo.required引用的JavaScript资源和DOM树已经可用。上述问题可以用dojo.addOnLoad解决。

dojo.addOnLoad接受一个函数作为参数并且确保该函数在满足下述三个条件后立即执行。

1.DOM树被浏览器创建并可以被客户代码使用。注意,这并不表示所有资源(例如图片)都被载入

2.所有的通过Dojo加载器请求的JavaScript资源都被载入

3.所有的Dojo小部件都被解析完毕

dojo.addOnLoad可以被调用任意多次,所有作为参数传入的函数严格按照他们被注册的顺序执行。dojo.addOnLoad的调用参数可以是一个函数的引用或是一个对象的函数名。下面是每种用法的示例:

下面是事件示例的完整代码,其中包含对dojo.addOnLoad的调用:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>利用dojo.addOnLoad执行初始化代码</title>
<script type="text/javascript" src="../../../dojoroot/dojo/dojo.js" djConfig="parseOnLoad:true"></script>
<script type="text/javascript">
// dojo.addOnLoad(f);//函数f
// dojo.addOnLoad(function(){});//一个函数字面量
// dojo.addOnLoad(o,"f");//函数o["f"]

function handleClick(eventObj){
    console.log(
        "Event("+eventObj.type+") on Dom node "+eventObj.target.id+";currentTarget= "+eventObj.currentTarget.id
    );

    // eventObj的类型是MouseEvent
    if(eventObj.shiftKey){
        //按下shift键并点击鼠标将阻止事件冒泡
        eventObj.stopPropagation();
    }
}
function connectAll(){
    dojo.connect(dojo.byId("body"),"click",handleClick);
    dojo.connect(dojo.byId("body-div"),"click",handleClick);
    dojo.connect(dojo.byId("body-div-p"),"click",handleClick);
    dojo.connect(dojo.byId("body-div-ol"),"click",handleClick);
    dojo.connect(dojo.byId("body-div-ol-li-1"),"click",handleClick);
    dojo.connect(dojo.byId("body-div-ol-li-2"),"click",handleClick);
    dojo.connect(dojo.byId("body-div-ol-li-3"),"click",handleClick);
    dojo.connect(dojo.byId("body-div-ol-li-4"),"click",handleClick);
    dojo.connect(dojo.byId("body-div-ol-li-5"),"click",handleClick);
}
dojo.addOnLoad(connectAll);
</script>
</head>
<body id="body">
    <div id="body-div">
        <p id="body-div-p">
            是理解事件的时候了
        </p>
        <ol id="body-div-ol">
            <li id="doby-div-ol-li-1">
                利用dojo.connect/disconnect链接/取消链接处理函数
            </li>
            <li id="doby-div-ol-li-2">
                总是向处理函数传递一个事情对象作为参数
            </li>
            <li id="doby-div-ol-li-3">
                不要用“this”引用当前目标
            </li>
            <li id="doby-div-ol-li-4">
                能冒泡的事件总是冒泡
            </li>
            <li id="doby-div-ol-li-5">
                完整的定义了键盘事件和相关的事件对象
            </li>
        </ol>
    </div>
</body>
</html>

以上就是关于Dojo DOM事件框架的全部内容:

1.dojo.connect/disconnect链接或取消链接处理函数

2.处理函数通常要接收一个与事件相关的事情对象以获取事件的详细信息

3.使用事件对象的target/currentTarget属性获取目标/当前目标DOM节点,而不使用this

4.能冒泡的事件通常都要冒泡,而捕获阶段通常被禁止

5.定义了键盘事件及其关联的事件对象

6.利用dojo.addOnLoad对那些把处理函数连接到事件的初始化函数进行注册

DOM事件分类

这里写图片描述

传给处理函数的事件对象的类型

事件是否支持冒泡(B表示支持)

事件相关默认处理过程能否被取消

版权声明:本文为博主原创文章,欢迎转载并标明出处。

相关文章推荐

(6)Dojo学习之DOM操作

引言 Dojo模块操作DOM 1 dojodom操作DOM结点 2 dojodom-construct操作DOM结点 21使用create方法操DOM 22 使用destroynode方法销毁一个结点...

web前端之精通dojo七:DOM工具

web前端之精通dojo七:DOM工具 文档:DOM中的”D”: 如果没有document(文档),DOM无从谈起。 对象:DOM中的”O”: 用户定义对象(user-defined objec...

web前端之精通dojo六:异步编程

web前端之精通dojo六:异步编程 利用Dojo关联用户自定义事件 function f(){ console.log("hello word"); }; function my...

web前端之精通dojo一:创建选项框表单

web前端之精通dojo一:创建web表单Dijit是建立在Dojo上的小部件系统,可以为你担当重任。小部件,又称Dijit组件,适用于HTML和JavaScript语言建立起的用户界面控件。你可以向...

web前端之精通dojo二:连接外部服务

web前端之精通dojo二:连接外部服务前面我们看到了dijit改善用户到浏览器的体验。现在我们将研究的重点放到浏览器这个过程中。Ajax,即异步JavaScript和XML,就是一种浏览器与服务器交...

web前端之精通dojo四:JavaScript中的语言扩展

web前端之精通dojo四:JavaScript中的语言扩展 Dojo提供了一些函数库,不严格地讲,这些函数扩展了JavaScript核心库。这些函数不正对某个特定的问题领域,它们是JavaScri...

web前端之dojo实际应用及开发五:丰富的用户界面(附有源码)

web前端之dojo实际应用及开发五:丰富的用户界面(附有源码)现在我们就使用dojo的Dijit工具包来丰富用户界面: 那Dijit的界面组件有哪些呢?日历、调色板、对话框(模态(modal)或非...

如何使用dojo.query 进行DOM查询和批量操作

入门   对DOM编程的一个关键要素是能够快速高效的获取到你所要使用的节点。之前我们曾经介绍过使用dojo.byId来查找DOM节点的方法。但是,这种方法的局限性也很明显。你很难为页面上每个节点都...

浅析dojo.connect的几种用法(一)——关联事件,不仅仅是DOM Event

介绍       每个流行的工具包中,总有一些异常出彩的闪光点。dojo.connect就是dojo工具包中,与JavaScript事件机制相关的重磅功能。       在JavaScript的使用场...
  • eengel
  • eengel
  • 2011年05月13日 09:56
  • 8340

Dojo Widget 中DOM事件的初始化和销毁

这篇帖子还是属于Dojo Widget系列吧。从上一篇dijit.layout.ContentPane 中的标准方法/事件在不同情况下的调用中,我们看到了dijit.layout.ContentPan...
  • eengel
  • eengel
  • 2011年07月11日 22:18
  • 3830
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:web前端之精通dojo五:利用Dojo进行DOM事件编程
举报原因:
原因补充:

(最多只允许输入30个字)