手机版

javaScript事件绑定、事件冒泡、事件捕获和事件执行顺序排序总结

时间:2021-09-07 来源:互联网 编辑:宝哥软件园 浏览:

我花时间学习了javascript和jquery的事件设计,收获很大。总结这篇文章并与你分享。

(一)事件绑定的几种方式

一般来说,javascript通过两种方式将事件处理程序绑定到DOM:html文档中的绑定和js代码中的绑定。下面的方法1和2属于html中的绑定事件,方法3、4和5属于js代码中的绑定事件,其中方法5是最推荐的方法。

模式1:

HTML的DOM元素支持以on开头的属性,比如onclick和on bulr,我们可以直接在这些属性值中编写javascript代码。当你点击div的时候,下面的代码会弹出div的ID:

div id=' Outesta ' onclick=' var id=this . id;警报(id);返回false'/div

这显然是不好的,因为代码都是放在字符串中的,无法格式化和排版,而且代码很多的时候很难理解。这里值得注意的是,onclick中的这个属性代表了当前被点击的DOM对象,所以我们可以通过这个. id得到DOM元素的id属性值。

模式2:

当有大量代码时,我们可以在onclick等属性中指定函数名。

脚本函数button handler(thisDom){ alert(this . id);//未定义的警报(thisDoM . id);//outestA返回false}/script div id=' outestA ' onclick=' return buttonHandler(this);'/div与上面的方法相比,这个方法稍微好一点。值得一提的是,事件处理程序中的这个表示window对象,所以我们在onclick属性值中将dom对象作为参数通过这个传递。

模式3:在JS代码中,通过dom元素的onclick和其他属性,

var DOM=document . getelementbyid(' outestA ');DOM . onclick=function(){ alert(' 1=' this . id);};DOM . onclick=function(){ alert(' 2=' this . id);};这样,这就代表了当前的DOM对象。还有一点:这样只能绑定一个事件处理程序,后者会覆盖前者。

方法4:使用attachEvent/disconnectevent函数绑定和取消4:IE下的事件。

附件事件/分离事件不兼容。IE6~IE11都支持这个功能,但是FF和Chrome浏览器不支持这个方法。并且attachEvent/disconnectevent不是W3C标准,所以不推荐使用。在IE浏览器下,attachEvent具有以下特点。

a)这在事件处理程序中表示一个窗口对象,而不是dom对象。

var DOM=document . getelementbyid(' outestA ');dom.attachEvent('onclick ',a);函数a(){ alert(this . id);//undefined }b)同一事件处理程序只能绑定一次。

var DOM=document . getelementbyid(' outestA ');dom.attachEvent('onclick ',a);dom.attachEvent('onclick ',a);函数a(){ alert(this . id);}虽然attachEvent被绑定了两次,但函数a只会被调用一次。

c)不同的功能对象可以重复绑定而不覆盖。

var DOM=document . getelementbyid(' outestA ');dom.attachEvent('onclick ',function(){ alert(1);});dom.attachEvent('onclick ',function(){ alert(1);});//当outestA的点击事件发生时,会弹出两个对话框。匿名函数和匿名函数互不相同,即使代码完全相同。因此,如果我们想用disconnectevent取消attachEvent绑定的事件处理程序,在绑定事件时就不能使用匿名函数,必须将事件处理程序写成单独的函数,否则就无法取消。

方法5:使用W3C标准的addEventListener和removeEventListener。

这两个功能是W3C标准规定的,FF和Chrome浏览器支持,IE6/IE7/IE8不支持。然而,这两个标准的API从IE9开始就得到支持。

//type:事件类型,不包括' on ',如' click ',' mouseover ',' keydown ';attachEvent的事件名称包含“on”,如“onclick”、“onmouseover”、“onkeydown”;//listener:事件处理函数//useCapture是事件冒泡或事件捕获。默认值为false,表示事件冒泡类型addEventListener(类型,Listener,use capture);a)这在事件处理程序中表示dom对象,而不是窗口,这与attachEvent不同。

var DOM=document . getelementbyid(' outestA ');dom.addEventListener('click ',a,false);函数a(){ alert(this . id);//outestA }b)同一个事件处理程序可以绑定两次,一次用于事件捕获,一次用于事件冒泡。

var DOM=document . getelementbyid(' outestA ');dom.addEventListener('click ',a,false);dom.addEventListener('click ',a,true);函数a(){ alert(this . id);//outestA }//当单击outestA时,函数a将被调用两次。如果绑定了同一个事件处理程序,并且两者都是事件冒泡类型或事件捕获类型,则只能绑定一次。

var DOM=document . getelementbyid(' outestA ');dom.addEventListener('click ',a,false);dom.addEventListener('click ',a,false);函数a(){ alert(this . id);//outestA }//单击outestA时,函数a只会被调用一次。c)可以重复绑定不同的事件处理程序,这与attachEvent是一致的。

(2)事件处理功能的执行顺序

模式1、模式2、模式3无法实现事件的重复绑定,自然不存在执行顺序的问题。模式4和模式5可以重复绑定特性,所以需要了解执行顺序。如果你写的代码依赖于执行顺序,你可以断定你的设计有问题。所以下面的顺序问题只是作为兴趣来讨论,没有实际意义。直接结论:addEventListener和attachEvent表现相同。如果多个处理函数绑定到同一个事件,首先绑定的函数将首先执行。下面的代码我已经在IE11、FF17和Chrome39中测试过了。

script window . onload=function(){ span style=' white-space : pre '/span var OUta=document . getelementbyid(' OUta ');outA.addEventListener('click '),function(){ alert(1);},false);outA.addEventListener('click '),function(){ alert(2);},真);outA.addEventListener('click '),function(){ alert(3);},真);outA.addEventListener('click '),function(){ alert(4);},真);};/script body div id=' OUta ' style=' width :400 px;高度:400 px;背景: # CDC 9 c 9;位置position:relative'/div/body当您单击outA时,将依次打印1、2、3和4。这里要特别注意:我们把几个onclick事件处理程序绑定到outA,这也是直接点击outA触发的事件,所以不涉及事件冒泡和事件捕获的问题,也就是说,addEventListener的第三个参数在这个场景中是没有用的。如果outA的click事件是由事件冒泡或事件捕获触发的,那么函数的执行顺序就会改变。

(3)事件冒泡和事件捕获

事件冒泡和事件捕捉很容易理解,但对同一件事的看法不同,但两种观点都很有道理。我们知道HTML中的元素可以嵌套形成类似于树的层次关系。例如,以下代码:

div id=' OUta ' style=' width :400 px;高度:400 px;背景: # CDC 9 c 9;位置position:relative'div id=' OutB ' style=' height :200;背景# 0000fftop:100px位置position:relative'div id=' OcT ' style=' height :100 px;背景# FFB90Ftop:50px位置position:relative'/div /div/div如果点击最里面的outC,是否点击最外面的outB和outC?显然,否则,没有必要区分事件冒泡和事件捕获,这一点在浏览器厂商中是毫无疑问的。如果outA、outB和OutT都注册了点击型事件处理函数,那么当OutT被点击时,触发序列是a-b-c还是c-b-a?如果浏览器使用事件冒泡,触发顺序为C-B-A,像气泡一样从底部向表面由内而外浮动;如果使用事件捕捉,触发顺序是a-b-c,从上到下,像石头一样,从水面落到水底。

事件冒泡如下图所示:

事件捕获见下图:

一般来说,事件冒泡机制用的比较多,所以在IE8之前,IE只支持事件冒泡。支持IE9 /FF/Chrome两种型号,可以使用addEvent Listener的useCapture进行设置((类型,监听器,使用Capture)。useCapture=false表示事件冒泡,useCapture=true表示事件捕获。

script window . onload=function(){ var OUta=document . getelementbyid(' OUta ');var outB=document . getelementbyid(' outB ');var OcT=document . GetElementBYid(' OcT ');//使用event bubbling out a . addevent listener(' click '),function(){ alert(1);},false);outB.addEventListener('click '),function(){ alert(2);},false);outC.addEventListener('click '),function(){ alert(3);},false);};/script body div id=' OUta ' style=' width :400 px;高度:400 px;背景: # CDC 9 c 9;位置position:relative'div id=' OutB ' style=' height :200;背景# 0000fftop:100px位置position:relative'div id=' OcT ' style=' height :100 px;背景# FFB90Ftop:50px位置position:relative'/div /div /div/body使用事件冒泡。点击Out时,打印顺序为3-2-1。如果将false更改为true以使用事件捕获,则打印顺序为1-2-3。

(4) DOM事件流

不知道怎么解释DOM事件流。个人感觉是事件冒泡和事件捕捉的结合。直接看图。

DOM事件流:事件分为三个阶段:捕获阶段、目标阶段和冒泡阶段。首先在捕获阶段调用处理函数,然后在目标阶段调用处理函数,最后在冒泡阶段调用处理函数。这个过程非常类似于Struts2框中的动作和拦截器。发送URL请求时,先调用前面的拦截器,再调用动作,最后调用后面的拦截器。

script window . onload=function(){ var OUta=document . getelementbyid(' OUta ');var outB=document . getelementbyid(' outB ');var OcT=document . GetElementBYid(' OcT ');//target(事件是自己触发、冒泡还是捕获都无所谓)outt . addeventlistener(' click '、function(){ alert(' target ');},真);//事件冒泡outa。addeventlistener ('click ',function(){ alert(' bubble 1 ');},false);outB.addEventListener('click ',function(){ alert(' bubble 2 ');},false);//事件捕获outa.addeventlistener ('click '),function(){ alert(' capture 1 ');},真);outB.addEventListener('click ',function(){ alert(' capture 2 ');},真);};/script body div id=' OUta ' style=' width :400 px;高度:400 px;背景: # CDC 9 c 9;位置position:relative'div id=' OutB ' style=' height :200;背景# 0000fftop:100px位置position:relative'div id=' OcT ' style=' height :100 px;背景# FFB90Ftop:50px位置position:relative'/div /div /div/body,当你点击outC,你会依次打印出capture 1-capture 2-Target-bubble 2-bubble 1。有可能理解API addeventlistener(类型、处理程序、usecapture)中第三个参数useCapture的含义吗?UseCapture=false表示事件处理程序被添加到冒泡阶段,并将在冒泡阶段被调用;UseCapture=true表示事件处理程序被添加到捕获阶段,并将在捕获阶段被调用。从DOM事件流模型可以看出,捕获阶段的事件处理函数必须在冒泡阶段的事件处理函数之前执行。

(5)再谈事件函数的执行顺序

DOM事件流中提到:

//target(事件是自己触发、冒泡还是捕获都无所谓)outt . addeventlistener(' click '、function(){ alert(' target ');},真);

我们在outC上触发onclick事件(这是目标对象)。如果我们同时在outC上绑定捕获阶段/气泡阶段事件处理函数会怎么样?

script window . onload=function(){ var OUta=document . getelementbyid(' OUta ');var outB=document . getelementbyid(' outB ');var OcT=document . GetElementBYid(' OcT ');//target(事件是由自身触发还是捕获无关紧要)out . addeventlistener(' click '、function(){ alert(' target 2 ');},真);outC.addEventListener('click '),function(){ alert(' target 1 ');},真);//事件冒泡outa。addeventlistener ('click ',function(){ alert(' bubble 1 ');},false);outB.addEventListener('click ',function(){ alert(' bubble 2 ');},false);//事件捕获outa.addeventlistener ('click '),function(){ alert(' capture 1 ');},真);outB.addEventListener('click ',function(){ alert(' capture 2 ');},真);};/script body div id=' OUta ' style=' width :400 px;高度:400 px;背景: # CDC 9 c 9;位置position:relative'div id=' OutB ' style=' height :200;背景# 0000fftop:100px位置position:relative'div id=' OcT ' style=' height :100 px;背景# FFB90Ftop:50px位置position:relative'/div /div /div/body点击outC时,打印顺序为: capture 1-capture 2-target 1-bubble 2-bubble 1。因为outC是触发事件的目标对象,所以在outC上注册的事件处理程序属于DOM事件流的目标阶段。目标阶段函数的执行顺序:先注册的先执行,后注册的再执行。以上就是我们说的。绑定在目标对象上的函数采用捕获还是冒泡并不重要,因为冒泡和补漏只对父元素上函数的执行顺序有影响,对本身没有影响。如果你不相信我,你可以把下面的代码放进去验证。

//target(事件是由自身触发还是捕获无关紧要)out . addeventlistener(' click '、function(){ alert(' target 1 ');},false);outC.addEventListener('click '),function(){ alert(' target 2 ');},真);outC.addEventListener('click '),function(){ alert(' target 3 ');},真);outC.addEventListener('click '),function(){ alert(' target 4 ');},false);此时,我们可以给出事件函数执行顺序的结论:首先执行捕获阶段的处理函数,然后执行目标阶段的处理函数,最后执行冒泡阶段的处理函数。在目标阶段,首先执行注册的处理功能,然后执行注册的处理功能。

(六)防止事件冒泡和捕捉

默认情况下,按照DOM事件流模型中的顺序执行多个事件处理程序。如果一个事件发生在一个子元素上,并且不需要执行在父元素上注册的事件处理程序,那么我们可以停止捕获和冒泡,以避免无意义的函数调用。上面提到的五种事件绑定方法可以防止事件的传播。因为第五种方法,所以是最推荐的做法。因此,在第五种方法的基础上,我们将看看如何防止事件的传播。IE8及之前,可以防止事件继续通过window . event . cancel ubble=true;IE9 /FF/Chrome通过event.stopPropagation()阻止事件的继续传播。

script window . onload=function(){ var OUta=document . getelementbyid(' OUta ');var outB=document . getelementbyid(' outB ');var OcT=document . GetElementBYid(' OcT ');//target outt . addevent listener(' click '),function(event){ alert(' target ');event . stopperpagation();},false);//事件冒泡outa。addeventlistener ('click '),function(){ alert(' bubble ');},false);//事件捕获outa.addeventlistener ('click '),function(){ alert(' capture ');},真);};/script body div id=' OUta ' style=' width :400 px;高度:400 px;背景: # CDC 9 c 9;位置position:relative'div id=' OutB ' style=' height :200;背景# 0000fftop:100px位置position:relative'div id=' OcT ' style=' height :100 px;背景# FFB90Ftop:50px位置position:relative'/div /div /div/body当您单击out时,您将打印出捕获目标,而不是气泡。因为当事件传播到Out上的处理程序时,会阻止事件继续通过stopPropagation传播,所以它不会继续传播到冒泡阶段。

最后,看一个更有趣的代码:

脚本窗口。onload=function(){ var OUta=document。getelementbyid(' OUta ');var outB=文档。getelementbyid(' OutB ');var OcT=文档。GetElementBYid(' OCt ');//目标outC.addEventListener('click '),function(event){ alert(' target ');},false);//事件冒泡outA.addEventListener('click '),function(){ alert(' bubble ');},false);//事件捕获outA.addEventListener('click '),function(){ alert(' capture ');事件。stopperpagation();},真);};/script body div id=' OUta ' style=' width :400 px;高度:400 px背景: #疾控中心9 c 9位置position : relative ' div id=' OutB ' style=' height :200;背景# 0000fftop:100px位置position : relative ' div id=' OCt ' style=' height :100 px;背景# FFB90Ftop:50px位置位置:相对/div /div/body执行结果是只打印捕捉,不会打印目标和泡泡。神奇吧,我们点击了出去,但是却没有触发在外上的事件处理函数,而是触发了离开上的事件处理函数。原因不做解释,如果你还不明白,可以再读一遍本文章。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

版权声明:javaScript事件绑定、事件冒泡、事件捕获和事件执行顺序排序总结是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。