JS事件

总结自一篇文章:

看懂此文,不再困惑于 JS 中的事件设计

(一)事件绑定的方式

总体为两种: html中绑定 | JS中绑定

1、html中绑定

​ 1) <div id="outA" onclick="var id=this.id;alert(id);return false;"></div>

​ 2) <div id="outA" onclick="return buttonHandler(this);"></div>

直接写JS代码或者一个函数调用。注意时间处理函数中的this代表window对象,所以需要通过this讲DOM对象作为参数传递。

2、JS中绑定

​ 1) dom.onclick = function(){alert(this.id);}

​ 函数中的this代表当前DOM对象。这种方法只能绑定一个时间处理函数,后面覆盖前面。

​ 2) IE使用attachEvent/detachEvent函数进行事件绑定和取消。就不说了。。。

​ 3) W3C标准方法: addEventListener/removeEventListener (IE 6/7/8 don not support)

dom.addEventListener(type, listener, useCapture)
//type:事件类型(不含on)
//listener:事件处理函数
//useCapture:默认为false,表示事件冒泡,true为事件捕获
dom.addEventListener('click', a, false);
function() {
  alert(this.id);
}

a) 事件处理函数中的this代表DOM对象

b) 同一个事件处理函数可以绑定两次,但必须一次是事件捕获,一次是事件冒泡

c) 不同的listener可重复绑定


(二)事件处理函数的执行顺序

如果给同一个事件绑定多个处理函数,先绑定的先执行

例如给outA元素绑定了多个onclick事件处理函数,在这种场景下不涉及到事件冒泡和捕获。否则执行顺序会有不同。


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

<div id="outA">
  <div id="outB">
    <div id="outC">      
    </div>
  </div>
</div>
//若点击了最内侧的outC,同样会触发outB和outA的点击事件,那么
//是执行A -> B -> C ? 还是 C -> B -> A ?

答案很简单:

若是事件冒泡,则是 C -> B -> A

若是事件捕获,则是 A -> B -> C


(四)DOM事件流

看图:

DOM事件流

DOM事件流有三个阶段:捕获阶段、目标阶段、冒泡阶段

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);
//捕获阶段

当点击outC元素时,依次打印出 capture1 -> capture2 -> target -> bubble2 -> bubble1

所以,

useCapture = false 意味着: 将listener加入到冒泡阶段

useCapture = true 意味着: 将listener加入到捕获阶段

若是outC同时绑定了冒泡和捕获,则先绑定的先执行。

结论

捕获阶段的事件处理函数先执行。

其次是目标阶段的。

最后是冒泡阶段的。

目标阶段的listener,先注册的先执行。


(五)阻止事件冒泡和捕获

IE8及以前:window.event.cancelBubble = true

iE9+/FF/chrome:event.stopPropagation()