DOM事件和事件委托

95 阅读2分钟

DOM 事件

DOM事件模型分为捕获和冒泡。一个事件发生后,会在子元素和父元素之间传播,这种传播分为三个阶段。

  • 捕获阶段:事件从window对象自上而下向目标节点传播,所有经过的节点,都会触发对应的事件
  • 目标阶段:目标节点处理事件
  • 冒泡阶段:事件从目标节点自下而上向window对象传播,同样,所有经过的 节点,都会触发对应的事件

!

addEventListener

  绑定事件对象.addEventListener(事件类型,回调函数,布尔值) 
  如:target.addEventListener('click',fntrue) 
  • 如果不传布尔值或为falsy值 -- fn就会走冒泡阶段,
  • 如果布尔值为true -- fn 就会走捕获阶段

代码示例:点击target

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  <style>
    div{
      border: 1px solid red;
      padding: 10px;
    }
  </style>
</head>

<body>
  <div class="parent">container
    <div class="child">box
      <div class="target">target</div>
    </div>
  </div>
</body>
<script>
  const $ = s => document.querySelector(s)
  $('.parent').addEventListener('click',function(e){
    console.log('在捕获阶段,parent 开始处理')
  },true)
  $('.child').addEventListener('click',function(e){
    console.log('在捕获阶段,child 开始处理')
  },true)
  $('.target').addEventListener('click',function(e){
    console.log('在捕获阶段,target 开始处理')
  },true)
    $('.parent').addEventListener('click',function(e){
    console.log('在冒泡阶段,parent 开始处理')
  },false)
  $('.child').addEventListener('click',function(e){
    console.log('在冒泡阶段,child 开始处理')
  },false)
  $('.target').addEventListener('click',function(e){
    console.log('在冒泡阶段,target 开始处理')
  },false)
</script>
</html>

// 

"在捕获阶段,parent 开始处理"
"在捕获阶段,child 开始处理"
"在捕获阶段,target 开始处理"
"在冒泡阶段,target 开始处理"
"在冒泡阶段,child 开始处理"
"在冒泡阶段,parent 开始处理"

阻止事件冒泡

e.stopPropagation()

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  <style>
    div{
      border: 1px solid red;
      padding: 10px;
    }
  </style>
</head>

<body>
  <div class="parent">container
    <div class="child">box
      <div class="target">target</div>
    </div>
  </div>
</body>
<script>
  const $ = s => document.querySelector(s)
  $('.parent').addEventListener('click',function(e){
    console.log('在捕获阶段,parent 开始处理')
  },true)
  $('.child').addEventListener('click',function(e){
  
  
  
    e.stopPropagation()
    
    
    
    console.log('在捕获阶段,child 开始处理')
  },true)
  $('.target').addEventListener('click',function(e){
    console.log('在捕获阶段,target 开始处理')
  },true)
    $('.parent').addEventListener('click',function(e){
    console.log('在冒泡阶段,parent 开始处理')
  },false)
  $('.child').addEventListener('click',function(e){
    console.log('在冒泡阶段,child 开始处理')
  },false)
  $('.target').addEventListener('click',function(e){
    console.log('在冒泡阶段,target 开始处理')
  },false)
</script>
</html>

//

"在捕获阶段,parent 开始处理"
"在捕获阶段,child 开始处理"

事件委托

事件委托又叫事件代理,由于冒泡阶段会从子节点向上传播到父节点,因此可以监听父节点来处理多个子节点的事件。

事件列表

有时我们会遇到一些问题,比如:

  • 你要给100个按钮做监听事件,咋办?
  • 你要监听目前不存在的元素的事件,咋办?

这个时候,可以监听这些元素的祖先,等冒泡或事件触发时判断是不是我想要监听的元素即可。

假设有10个按钮

HTML

<!DOCTYPE>
<html>

<head>
  <meta charset='UTF-8'>
  <title>事件委托</title>

  <head>

    <body>
      <div class='btn'>
        <button>btn1</button>
        <button>btn2</button>
        <button>btn3</button>
        <button>btn4</button>
        <button>btn5</button>
        <button>btn6</button>
        <button>btn7</button>
        <button>btn8</button>
        <button>btn9</button>
        <button>btn10</button>
      </div>
      <script>
      </script>
    </body>
    <html>

JS

// 监听祖先元素
 const btn = document.querySelector('.btn')

 btn.addEventListener('click', (e) => {
   const t = e.target
   if (t.tagName.toLowerCase() === 'button') {
     console.log('button被点击了');
     console.log('被点击的button是' + t.textContent);
   }
 })
 
 // 
 
 点击btn2  
 
"button被点击了"
"被点击的button是btn2"

button一开始不存在

HTMl

 <!DOCTYPE html>
  <html>
  <head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  </head>
<body>
  <div id=div1></div>
</body>
</html>

JS

setTimeout(()=>{
  const button = document.createElement('button')
  button.textContent = 'click'
  div1.appendChild(button)
},1000)

div1.addEventListener('click',(e)=>{
  const t = e.target
  if(t.tagName.toLowerCase() === 'button'){
    console.log('button 被 点击了')
  }
})

//

"button 被 点击了"

这也是事件委托的优点:

  • 省监听数(内存)
  • 可以监听动态元素