好!欢迎访问迷津渡口 现在时间是:

迷津渡口

越感到迷惑 越接近真理

事件捕获、事件冒泡和事件委托

事件捕获和事件冒泡

事件捕获和事件冒泡是浏览器处理事件的两种顺序,IE9之前IE只有事件冒泡,IE9+、Chrome、火狐等两者皆有。


事件捕获是从根元素往下找,直到找到事件触发的真正DOM元素,因此事件触发顺序为外层事件到内层事件。


事件冒泡是从实际触发事件的元素出发,事件向外层元素冒泡,直到根元素,因此事件触发顺序为内层事件到外层事件。


支持两者的浏览器处理顺序为:

  1. 优先查找事件捕获,若注册了捕获事件,则从最外层开始触发;

  2. 事件捕获完成后,找到触发事件的最内层元素,向外进行事件冒泡


默认:事件冒泡

点击div4,未注册捕获事件,因此处理顺序为触发事件的最内层向外冒泡,弹出顺序为div4,div3,div2,div1

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>默认情况-事件冒泡</title>
<style>
#div1 {
  width: 400px;
  height: 400px;
  background-color: red;
}
#div2 {
  width: 300px;
  height: 300px;
  background-color: blue;
}
#div3 {
  width: 200px;
  height: 200px;
  background-color:green;
}
#div4 {
  width: 100px;
  height: 100px;
  background-color: gold;
}
.right-bottom {
  display: flex;
  justify-content: flex-end;
  align-items: flex-end;
}
</style>
</head>
<body>
<div id="div1" class="right-bottom">
  <div id="div2" class="right-bottom">
    <div id="div3" class="right-bottom">
      <div id="div4"></div>
    </div>
  </div>
</div>
<script>
var div1 = document.querySelector('#div1'),
  div2 = document.querySelector('#div2'),
  div3 = document.querySelector('#div3'),
  div4 = document.querySelector('#div4');
  
div1.addEventListener('click', function(event) {
  alert(event.currentTarget.id)
})
div2.addEventListener('click', function(event) {
  alert(event.currentTarget.id)
})
div3.addEventListener('click', function(event) {
  alert(event.currentTarget.id)
})
div4.addEventListener('click', function(event) {
  alert(event.currentTarget.id)
})
</script>
</body>
</html>


修改为事件捕获:

点击div4,都注册了捕获事件,从最外层开始捕获触发事件,因此弹出顺序为div1,div2,div3,div4

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>自定义-事件捕获</title>
<style>
#div1 {
  width: 400px;
  height: 400px;
  background-color: red;
}
#div2 {
  width: 300px;
  height: 300px;
  background-color: blue;
}
#div3 {
  width: 200px;
  height: 200px;
  background-color:green;
}
#div4 {
  width: 100px;
  height: 100px;
  background-color: gold;
}
.right-bottom {
  display: flex;
  justify-content: flex-end;
  align-items: flex-end;
}
</style>
</head>
<body>
<div id="div1" class="right-bottom">
  <div id="div2" class="right-bottom">
    <div id="div3" class="right-bottom">
      <div id="div4"></div>
    </div>
  </div>
</div>
<script>
var div1 = document.querySelector('#div1'),
  div2 = document.querySelector('#div2'),
  div3 = document.querySelector('#div3'),
  div4 = document.querySelector('#div4');
  
div1.addEventListener('click', function(event) {
  alert(event.currentTarget.id)
}, true)
div2.addEventListener('click', function(event) {
  alert(event.currentTarget.id)
}, true)
div3.addEventListener('click', function(event) {
  alert(event.currentTarget.id)
}, true)
div4.addEventListener('click', function(event) {
  alert(event.currentTarget.id)
}, true)
</script>
</body>
</html>


混合事件捕获和事件冒泡:

给div1和div3加上事件捕获,则点击div4,先从外层向内层进行事件捕获的触发,先弹出div1,div3,然后进入触发事件的最内层元素,开始进行事件冒泡,再弹出div4,div2,因此触发顺序为div1,div3,div4,div2

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>混合事件捕获和事件冒泡</title>
<style>
#div1 {
  width: 400px;
  height: 400px;
  background-color: red;
}
#div2 {
  width: 300px;
  height: 300px;
  background-color: blue;
}
#div3 {
  width: 200px;
  height: 200px;
  background-color:green;
}
#div4 {
  width: 100px;
  height: 100px;
  background-color: gold;
}
.right-bottom {
  display: flex;
  justify-content: flex-end;
  align-items: flex-end;
}
</style>
</head>
<body>
<div id="div1" class="right-bottom">
  <div id="div2" class="right-bottom">
    <div id="div3" class="right-bottom">
      <div id="div4"></div>
    </div>
  </div>
</div>
<script>
var div1 = document.querySelector('#div1'),
  div2 = document.querySelector('#div2'),
  div3 = document.querySelector('#div3'),
  div4 = document.querySelector('#div4');
  
div1.addEventListener('click', function(event) {
  alert(event.currentTarget.id)
}, true)
div2.addEventListener('click', function(event) {
  alert(event.currentTarget.id)
})
div3.addEventListener('click', function(event) {
  alert(event.currentTarget.id)
}, true)
div4.addEventListener('click', function(event) {
  alert(event.currentTarget.id)
})
</script>
</body>
</html>


事件委托

事件委托是利用事件冒泡的原理,将子元素触发的事件冒泡到父元素进行处理,从而无需进行大量子元素的事件绑定,同时子元素动态变化时也无需重新绑定事件,因此大大提高了效率,优化了处理的方法。

例子:列表项鼠标悬停时字体变红,点击按钮可新增一个列表项

不使用事件委托的方式:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>不使用事件委托的例子</title>
</head>
<body>
<ul>
  <li>111111</li>
  <li>222222</li>
  <li>333333</li>
</ul>
<button id="add-item-btn">新增列表项</button>
<script>
var lis = document.querySelectorAll('li')
lis.forEach(function(item) {
  item.addEventListener('mouseover', function() {
    item.style.color = 'red'
  })
  item.addEventListener('mouseout', function() {
    item.style.color = 'black'
  })
})

var btn = document.querySelector('#add-item-btn')
var ul = document.querySelector('ul');
btn.addEventListener('click', function() {
  var item = document.createElement('li')
  item.innerText = '444444'
  /*需要重新绑定事件*/
  item.addEventListener('mouseover', function() {
    item.style.color = 'red'
  })
  item.addEventListener('mouseout', function() {
    item.style.color = 'black'
  })
  ul.appendChild(item)
})
</script>
</body>
</html>


使用事件委托的方式:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>使用事件委托的例子</title>
</head>
<body>
<ul>
  <li>111111</li>
  <li>222222</li>
  <li>333333</li>
</ul>
<button id="add-item-btn">新增列表项</button>
<script>
var btn = document.querySelector('#add-item-btn')
var ul = document.querySelector('ul');
ul.addEventListener('mouseover', function(event) {
  if (event.target.tagName.toUpperCase() === 'LI') {
    event.target.style.color = 'red'
  }
})
ul.addEventListener('mouseout', function(event) {
  if (event.target.tagName.toUpperCase() === 'LI') {
    event.target.style.color = 'black'
  }
})
btn.addEventListener('click', function() {
  var item = document.createElement('li')
  item.innerText = '444444'
  /*不需要重新绑定事件*/
  ul.appendChild(item)
})
</script>
</body>
</html>


事件委托的方式代码简单,效率较高~

点赞4
   支持一下
挤眼 亲亲 咆哮 开心 想想 可怜 糗大了 委屈 哈哈 小声点 右哼哼 左哼哼 疑问 坏笑 赚钱啦 悲伤 耍酷 勾引 厉害 握手 耶 嘻嘻 害羞 鼓掌 馋嘴 抓狂 抱抱 围观 威武 给力
 点赞
 签到
 表情
 图片
 代码
提交评论

清空信息
关闭评论
 00:00/00:00
我想和你虚度时光 - 花房姑娘(9)
  1. 恋恋风尘
  2. 恋恋风尘
  3. 恋恋风尘
  4. 恋恋风尘
  5. 恋恋风尘
  6. 恋恋风尘
  7. 恋恋风尘
  8. 恋恋风尘
  9. 恋恋风尘