链接:////
抽空学习了下和的事件设计,收获颇大,总结此贴,和大家分享。
(一)事件绑定的几种方式
给DOM绑定事件处理函数总的来说有2种方式:在html文档中绑定、在js代码中绑定。下面的方式1、方式2属于在html中绑定事件,方式3、方式4和方式5属于在js代码中绑定事件,其中方法5是最推荐的做法。
方式1:
HTML的DOM元素支持、等以on开头属性,我们可以直接在这些属性值中编写代码。当点击div的时候,下面的代码会弹出div的ID:
这种做法很显然不好,因为代码都是放在字符串里的,不能格式化和排版,当代码很多的时候很难看懂。这里有一点值得说明:属性中的this代表的是当前被点击的DOM对象,所以我们可以通过this.id获取DOM元素的id属性值。
方式2:
当代码比较多的时候,我们可以在等属性中指定函数名。
跟上面的做法相比,这种做法略好一些。值得一提的是:事件处理函数中的this代表的是对象,所以我们在属性值中,通过this将dom对象作为参数传递。
方式3:在JS代码中通过dom元素的等属性
= .("");
dom. = (){alert("1=" + this.id);};
dom. = (){alert("2=" + this.id);};
这种做法this代表当前的DOM对象。还有一点:这种做法只能绑定一个事件处理函数,后面的会覆盖前面的。
方式4:IE下使用/函数进行事件绑定和取消。
/兼容性不好,IE6~IE11都支持该函数,但是FF和浏览器都不支持该方法。而且/不是W3C标准的做法,所以不推荐使用。在IE浏览器下,有以下特点。
a) 事件处理函数中this代表的是对象,不是dom对象。
= .("");
dom.('',a);
()
alert(this.id);//
b) 同一个事件处理函数只能绑定一次。
= .("");
dom.('',a);
dom.('',a);
()
alert(this.id);
虽然使用绑定了2次,但是函数a只会调用一次。
c)不同的函数对象,可以重复绑定,不会覆盖。
= .("");
dom.('',(){alert(1);});
dom.('',(){alert(1);});
// 当的click事件发生时,会弹出2个对话框
匿名函数和匿名函数是互相不相同的,即使代码完全一样。所以如果我们想用取消绑定的事件处理函数,那么绑定事件的时候不能使用匿名函数,必须要将事件处事函数单独写成一个函数,否则无法取消。
方式5:使用W3C标准的和。
这2个函数是W3C标准规定的,FF和浏览器都支持,IE6/IE7/IE8都不支持这2个函数。不过从IE9开始就支持了这2个标准的API。
// type:事件类型,不含"on",比如"click"、""、"";
// 而的事件名称,含含"on",比如""、""、"";
// :事件处理函数
// 是事件冒泡,还是事件捕获,默认false,代表事件冒泡类型
(type,,);
a) 事件处理函数中this代表的是dom对象,不是,这个特性与不同。
= .("");
dom.('click',a,false);
()
alert(this.id);//
b) 同一个事件处理函数可以绑定2次,一次用于事件捕获,一次用于事件冒泡。
= .("");
dom.('click',a,false);
dom.('click',a,true);
()
alert(this.id);//
// 当点击的时候,函数a会调用2次
如果绑定的是同一个事件处理函数,并且都是事件冒泡类型或者事件捕获类型,那么只能绑定一次。
= .("");
dom.('click',a,false);
dom.('click',a,false);
()
alert(this.id);//
// 当点击的时候,函数a只会调用1次
c) 不同的事件处理函数可以重复绑定,这个特性与一致。
(二)事件处理函数的执行顺序
方式1、方式2和方式3都不能实现事件的重复绑定,所以自然也就不存在执行顺序的问题。方式4和方式5可以重复绑定特性,所以需要了解下执行顺序的问题。如果你写出依赖于执行顺序的代码,可以断定你的设计存在问题。所以下面的顺序问题,仅作为兴趣探讨,没有什么实际意义。直接上结论:和表现一致,如果给同一个事件绑定多个处理函数,先绑定的先执行。下面的代码我在IE11、FF17和都测试过。
id="outA"style="width:400px; :400px; :#;:;">
id="outB"style=":200; :#;top:100px;:;">
id="outC"style=":100px; :#;top:50px;:;">
使用的是事件冒泡JS 取消默认事件,当点击outC的时候,打印顺序是3–>2–>1。如果将false改成true使用事件捕获,打印顺序是1–>2–>3。
(四) DOM事件流
DOM事件流我也不知道怎么解释,个人感觉就是事件冒泡和事件捕获的结合体,直接看图吧。
DOM事件流:将事件分为三个阶段:捕获阶段、目标阶段、冒泡阶段。先调用捕获阶段的处理函数,其次调用目标阶段的处理函数,最后调用冒泡阶段的处理函数。这个过程很类似于框中的和。当发出一个URL请求的时候,先调用前置拦截器,其次调用,最后调用后置拦截器。
id="outA"style="width:400px; :400px; :#;:;">
id="outB"style=":200; :#;top:100px;:;">
id="outC"style=":100px; :#;top:50px;:;">
当点击outC的时候,依次打印出–>–>–>–>。到这里是不是可以理解(type,,)这个API中第三个参数的含义呢?=false意味着:将事件处理函数加入到冒泡阶段,在冒泡阶段会被调用;=true意味着:将事件处理函数加入到捕获阶段,在捕获阶段会被调用。从DOM事件流模型可以看出,捕获阶段的事件处理函数,一定比冒泡阶段的事件处理函数先执行。
(五) 再谈事件函数执行先后顺序
在DOM事件流中提到过:
// 目标(自身触发事件,是冒泡还是捕获无所谓)
outC.('click',(){alert("");},true);
我们在outC上触发事件(这个是目标对象),如果我们在outC上同时绑定捕获阶段/冒泡阶段事件处理函数会怎么样呢?
id="outA"style="width:400px; :400px; :#;:;">
id="outB"style=":200; :#;top:100px;:;">
id="outC"style=":100px; :#;top:50px;:;">
点击outC的时候,打印顺序是:–>–>–>–>–>。由于outC是我们触发事件的目标对象,在outC上注册的事件处理函数,属于DOM事件流中的目标阶段。目标阶段函数的执行顺序:先注册的先执行,后注册的后执行。这就是上面我们说的,在目标对象上绑定的函数是采用捕获,还是采用冒泡,都没有什么关系,因为冒泡和捕获只是对父元素上的函数执行顺序有影响,对自己没有什么影响。如果不信,可以将下面的代码放进去验证。
// 目标(自身触发事件,是冒泡还是捕获无所谓)
outC.('click',(){alert("");},false);
outC.('click',(){alert("");},true);
outC.('click',(){alert("");},true);
outC.('click',(){alert("");},false);
至此我们可以给出事件函数执行顺序的结论了:捕获阶段的处理函数最先执行,其次是目标阶段的处理函数,最后是冒泡阶段的处理函数。目标阶段的处理函数,先注册的先执行,后注册的后执行。
(六) 阻止事件冒泡和捕获
默认情况下,多个事件处理函数会按照DOM事件流模型中的顺序执行。如果子元素上发生某个事件,不需要执行父元素上注册的事件处理函数,那么我们可以停止捕获和冒泡,避免没有意义的函数调用。前面提到的5种事件绑定方式,都可以实现阻止事件的传播。由于第5种方式,是最推荐的做法。所以我们基于第5种方式,看看如何阻止事件的传播行为。IE8以及以前可以通过 .event.=true阻止事件的继续传播;IE9+/FF/通过event.()阻止事件的继续传播。
id="outA"style="width:400px; :400px; :#;:;">
id="outB"style=":200; :#;top:100px;:;">
id="outC"style=":100px; :#;top:50px;:;">
当点击outC的时候JS 取消默认事件,之后打印出–>,不会打印出。因为当事件传播到outC上的处理函数时,通过阻止了事件的继续传播,所以不会继续传播到冒泡阶段。
最后再看一段更有意思的代码:
id="outA"style="width:400px; :400px; :#;:;">
id="outB"style=":200; :#;top:100px;:;">
id="outC"style=":100px; :#;top:50px;:;">
执行结果是只打印,不会打印和。神奇吧,我们点击了outC,但是却没有触发outC上的事件处理函数,而是触发了outA上的事件处理函数。原因不做解释,如果你还不明白,可以再读一遍本文章。
【今日微信公号推荐↓】
限时特惠:本站持续每日更新海量各大内部创业课程,一年会员仅需要98元,全站资源免费下载
点击查看详情
站长微信:Jiucxh