js事件冒泡和事件捕获

前段时间开发一个小项目的时候遇到一个问题,即给一个元素以及它的父元素绑定了click事件,这个时候我点击这个元素时,父级元素的clik事件也会触发,这显然不符合要求。查阅了一些资料以后才知道原来这就是事件冒泡,下面是我对事件冒泡和事件捕获的理解。javascript

事件冒泡:事件从目标子元素向父级元素逐级传递(目标div -> 父元素 —> body ->html ->document)
事件捕获:事件从最顶级元素向目标子元素逐级传递(document -> html -> body -> 父级元素 -> 目标div)css

我理解的事件捕获和事件冒泡其实就是浏览器事件触发的两个阶段。
在不支持w3c标准的浏览器(IE9如下)中,咱们用attachEvent(event, fn)方法绑定一个事件时,fn函数只能在冒泡阶段执行且只能在冒泡阶段执行。
在支持w3c标准的浏览器中,咱们用addEventListener(event, fn, useCapture)方法绑定一个事件时,其中的useCapture参数即用来指定fn函数是在捕获阶段执行仍是在冒泡阶段执行,默认false为冒泡执行,ture为捕获执行。一般为了兼容老版本的IE浏览器(IE如下),咱们不设置useCapture参数,或设置成falsehtml

下面是示例代码java

html代码:node

<style type="text/css">
    .parent {height: 120px; width: 120px; background-color: #999; padding: 25px;}
    .child {height: 60px; width: 60px; background-color: #666}
    
  </style>

  <body>
      <div class="parent" id="parent">
      <div class="child" id="child"></div> 
    </div>
  </body>

事件冒泡js代码:浏览器

var parent = document.getElementById('parent')
var child = document.getElementById('child')

// click事件冒泡时触发(useCapture参数为false和不加参数时的默认行为)
parent.addEventListener('click', function(e) {
  console.log('parent')
}, false)

child.addEventListener('click', function(e) {
  console.log('child')
  // e.stopPropagation()    // 阻止事件冒泡
}, false)

这个时候点击child元素,控制台会依次弹出child parent,所以事件触发的顺序是child ->parent, 固然若是咱们但愿点击child元素以后不触发parent元素的click事件,也能够用stopPropagation()来阻止事件的冒泡。函数

事件捕获js代码:性能

// click事件捕获时触发
parent.addEventListener('click', function(e) {
  console.log('parent')
}, true)

child.addEventListener('click', function(e) {
  console.log('child')
}, true)

这个时候点击child元素,控制台会依次弹出parent child,所以事件触发的顺序是parent->child.net

说了那么多,事件冒泡究竟有什么用呢? 下面咱们就利用事件冒泡原理来实现事件委托code

事件委托:

什么是事件委托? 事件委托就是本来你要给一个元素绑定某个事件,可是你不直接绑定在这个元素上,而是绑定在与它相关的元素上,可是效果与绑定在这个元素上同样。 这样作有什么好处呢? 下面咱们作个小例子,当鼠标移动到li上时改变它的背景颜色,鼠标离开时背景颜色恢复

html代码:

<body>
    <ul id="parent">
       <li>item1</li>
       <li>item2</li>
       <li>item3</li>
       <li>item4</li>
       <li>item5</li>
    </ul>
</body>

js代码:

var oParent = document.getElementById("parent");
var oItem = oParent.getElementsByTagName("li");

// 给ul绑定鼠标移入事件
oParent.addEventListener('mouseover', function(e) {
  if(e.target.nodeName.toLowerCase() == "li"){
    e.target.style.background = "red";
  }
})

// 给ul绑定鼠标移出事件
oParent.addEventListener('mouseout', function(e) {
  if(e.target.nodeName.toLowerCase() == "li"){
    e.target.style.background = "";
  }
})

固然你会说我也能够利用循环遍历为每一个li都绑定鼠标移入移出事件,固然这是能够的,可是这样你的代码就多了一个循环操做,若是循环多了以后对性能影响就不可忽略了。
还有就是若是你又动态的增长了一个<li>标签,那么你又不得不为这个li标签单独绑定事件,而采用事件委托这些烦恼均可以省略。

本文参考文章:
js之事件冒泡详解 http://www.jb51.net/article/4...
事件委托及其原理 http://www.cnblogs.com/dearxi...

相关文章
相关标签/搜索