转载自:http://blog.csdn.net/aitangyong/article/details/43231111
抽空学习了下javascript和jquery的事件设计,收获颇大,总结此贴,和大家分享。
(一)事件绑定的几种方式
方式1:
HTML的DOM元素支持onclick、onblur等以on开头属性,我们可以直接在这些属性值中编写javascript代码。当点击div的时候,下面的代码会弹出div的ID:
- <div id="outestA" onclick="var id = this.id;alert(id);return false;"></div>
这种做法很显然不好,因为代码都是放在字符串里的,不能格式化和排版,当代码很多的时候很难看懂。这里有一点值得说明:onclick属性中的this代表的是当前被点击的DOM对象,所以我们可以通过this.id获取DOM元素的id属性值。
方式2:
当代码比较多的时候,我们可以在onclick等属性中指定函数名。
- <script>
- function buttonHandler(thisDom)
- {
- alert(this.id);//undefined
- alert(thisDom.id);//outestA
- return false;
- }
- </script>
- <div id="outestA" onclick="return buttonHandler(this);"></div>
跟上面的做法相比,这种做法略好一些。值得一提的是:事件处理函数中的this代表的是window对象,所以我们在onclick属性值中,通过this将dom对象作为参数传递。
方式3:在JS代码中通过dom元素的onclick等属性
- var dom = document.getElementById("outestA");
- dom.onclick = function(){alert("1=" + this.id);};
- dom.onclick = function(){alert("2=" + this.id);};
这种做法this代表当前的DOM对象。还有一点:这种做法只能绑定一个事件处理函数,后面的会覆盖前面的。
方式4:IE下使用attachEvent/detachEvent函数进行事件绑定和取消。
attachEvent/detachEvent兼容性不好,IE6~IE11都支持该函数,但是FF和Chrome浏览器都不支持该方法。而且attachEvent/detachEvent不是W3C标准的做法,所以不推荐使用。在IE浏览器下,attachEvent有以下特点。
a) 事件处理函数中this代表的是window对象,不是dom对象。
- var dom = document.getElementById("outestA");
- dom.attachEvent('onclick',a);
- function a()
- {
- alert(this.id);//undefined
- }
- var dom = document.getElementById("outestA");
- dom.attachEvent('onclick',a);
- dom.attachEvent('onclick',a);
- function a()
- {
- alert(this.id);
- }
- var dom = document.getElementById("outestA");
- dom.attachEvent('onclick',function(){alert(1);});
- dom.attachEvent('onclick',function(){alert(1);});
- // 当outestA的click事件发生时,会弹出2个对话框
方式5:使用W3C标准的addEventListener和removeEventListener。
- // type:事件类型,不含"on",比如"click"、"mouseover"、"keydown";
- // 而attachEvent的事件名称,含含"on",比如"onclick"、"onmouseover"、"onkeydown";
- // listener:事件处理函数
- // useCapture是事件冒泡,还是事件捕获,默认false,代表事件冒泡类型
- addEventListener(type, listener, useCapture);
- var dom = document.getElementById("outestA");
- dom.addEventListener('click', a, false);
- function a()
- {
- alert(this.id);//outestA
- }
- var dom = document.getElementById("outestA");
- dom.addEventListener('click', a, false);
- dom.addEventListener('click', a, true);
- function a()
- {
- alert(this.id);//outestA
- }
- // 当点击outestA的时候,函数a会调用2次
- var dom = document.getElementById("outestA");
- dom.addEventListener('click', a, false);
- dom.addEventListener('click', a, false);
- function a()
- {
- alert(this.id);//outestA
- }
- // 当点击outestA的时候,函数a只会调用1次
c) 不同的事件处理函数可以重复绑定,这个特性与attachEvent一致。
(二)事件处理函数的执行顺序
- <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);},true);
- outA.addEventListener('click',function(){alert(3);},true);
- outA.addEventListener('click',function(){alert(4);},true);
- };
- </script>
- <body>
- <div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
- </div>
- </body>
(三) 事件冒泡和事件捕获
- <div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
- <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
- <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div>
- </div>
- </div>
事件冒泡见下图:
事件捕获见下图:
一般来说事件冒泡机制,用的更多一些,所以在IE8以及之前,IE只支持事件冒泡。IE9+/FF/Chrome这2种模型都支持,可以通过addEventListener((type, listener, useCapture)的useCapture来设定,useCapture=false代表着事件冒泡,useCapture=true代表着采用事件捕获。
- <script>
- window.onload = function(){
- var outA = document.getElementById("outA");
- var outB = document.getElementById("outB");
- var outC = document.getElementById("outC");
- // 使用事件冒泡
- outA.addEventListener('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:400px; height:400px; background:#CDC9C9;position:relative;">
- <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
- <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div>
- </div>
- </div>
- </body>
(四) DOM事件流
DOM事件流我也不知道怎么解释,个人感觉就是事件冒泡和事件捕获的结合体,直接看图吧。
DOM事件流:将事件分为三个阶段:捕获阶段、目标阶段、冒泡阶段。先调用捕获阶段的处理函数,其次调用目标阶段的处理函数,最后调用冒泡阶段的处理函数。这个过程很类似于Struts2框中的action和Interceptor。当发出一个URL请求的时候,先调用前置拦截器,其次调用action,最后调用后置拦截器。
- <script>
- window.onload = function(){
- var outA = document.getElementById("outA");
- var outB = document.getElementById("outB");
- var outC = document.getElementById("outC");
- // 目标(自身触发事件,是冒泡还是捕获无所谓)
- outC.addEventListener('click',function(){alert("target");},true);
- // 事件冒泡
- outA.addEventListener('click',function(){alert("bubble1");},false);
- outB.addEventListener('click',function(){alert("bubble2");},false);
- // 事件捕获
- outA.addEventListener('click',function(){alert("capture1");},true);
- outB.addEventListener('click',function(){alert("capture2");},true);
- };
- </script>
- <body>
- <div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
- <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
- <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div>
- </div>
- </div>
- </body>
(五) 再谈事件函数执行先后顺序
在DOM事件流中提到过:
- // 目标(自身触发事件,是冒泡还是捕获无所谓)
- outC.addEventListener('click',function(){alert("target");},true);
- <script>
- window.onload = function(){
- var outA = document.getElementById("outA");
- var outB = document.getElementById("outB");
- var outC = document.getElementById("outC");
- // 目标(自身触发事件,是冒泡还是捕获无所谓)
- outC.addEventListener('click',function(){alert("target2");},true);
- outC.addEventListener('click',function(){alert("target1");},true);
- // 事件冒泡
- outA.addEventListener('click',function(){alert("bubble1");},false);
- outB.addEventListener('click',function(){alert("bubble2");},false);
- // 事件捕获
- outA.addEventListener('click',function(){alert("capture1");},true);
- outB.addEventListener('click',function(){alert("capture2");},true);
- };
- </script>
- <body>
- <div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
- <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
- <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div>
- </div>
- </div>
- </body>
- // 目标(自身触发事件,是冒泡还是捕获无所谓)
- outC.addEventListener('click',function(){alert("target1");},false);
- outC.addEventListener('click',function(){alert("target2");},true);
- outC.addEventListener('click',function(){alert("target3");},true);
- outC.addEventListener('click',function(){alert("target4");},false);
(六) 阻止事件冒泡和捕获
默认情况下,多个事件处理函数会按照DOM事件流模型中的顺序执行。如果子元素上发生某个事件,不需要执行父元素上注册的事件处理函数,那么我们可以停止捕获和冒泡,避免没有意义的函数调用。前面提到的5种事件绑定方式,都可以实现阻止事件的传播。由于第5种方式,是最推荐的做法。所以我们基于第5种方式,看看如何阻止事件的传播行为。IE8以及以前可以通过 window.event.cancelBubble=true阻止事件的继续传播;IE9+/FF/Chrome通过event.stopPropagation()阻止事件的继续传播。
- <script>
- window.onload = function(){
- var outA = document.getElementById("outA");
- var outB = document.getElementById("outB");
- var outC = document.getElementById("outC");
- // 目标
- outC.addEventListener('click',function(event){
- alert("target");
- event.stopPropagation();
- },false);
- // 事件冒泡
- outA.addEventListener('click',function(){alert("bubble");},false);
- // 事件捕获
- outA.addEventListener('click',function(){alert("capture");},true);
- };
- </script>
- <body>
- <div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
- <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
- <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div>
- </div>
- </div>
- </body>
最后再看一段更有意思的代码:
- <script>
- window.onload = function(){
- var outA = document.getElementById("outA");
- var outB = document.getElementById("outB");
- var outC = document.getElementById("outC");
- // 目标
- outC.addEventListener('click',function(event){alert("target");},false);
- // 事件冒泡
- outA.addEventListener('click',function(){alert("bubble");},false);
- // 事件捕获
- outA.addEventListener('click',function(){alert("capture");event.stopPropagation();},true);
- };
- </script>
- <body>
- <div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
- <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
- <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div>
- </div>
- </div>
- </body>