js的dom事件流、事件委托和阻止绑定事件触发

主要讲解事件绑定和事件委托,onclick事件和addEventListener的区别

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .father {
      width: 100%;
      height: 300px;
      display: flex;
    }
    .child {
      width: 100px;
      height: 100px;
      background-color: aquamarine;
      margin: 10px;
    }
  </style>
</head>
<body>
  <div class="father">
    <div class="child">1</div>
    <div class="child">2</div>
    <div class="child">3</div>
    <div class="child">4</div>
    <div class="child">5</div>
  </div>
</body>
</html>

示例1:给元素绑定click点击事件

使用onclick

  • 重复绑定点击事件,后面的事件会覆盖前面的事件
<script>
  const element = document.querySelector('.father')
  element.onclick = () => {
    console.log('点击事件1')
  }
  element.onclick = () => {
    console.log('点击事件2')
  }
  // 控制台只会输出:点击事件2
</script>

使用addEventListener

  • 重复绑定点击事件,事件不会被覆盖(类似于发布订阅模式,on中收集的事件存放在数组中,在emit时会遍历执行事件)
  <script>
    const element = document.querySelector('.father')
    element.addEventListener('click', () => {
      console.log('点击事件1')
    })
    element.addEventListener('click', () => {
      console.log('点击事件2')
    })
    // 控制台输出 点击事件1 点击事件2
  </script>

语法:document.addEventListener(event, function, useCapture)
useCapture是可选的布尔值,指定事件是否在捕获或冒泡阶段执行

  • true:事件在捕获阶段执行
  • false:默认值,事件在冒泡阶段执行
element .addEventListener('click', (el) => {
  console.log(el.currentTarget) // 当前绑定事件的元素
  console.log(el.target) // 点击事件触发的元素
})

示例2:默认给每个child元素绑定一个点击事件,现在如果class名包含out-box的元素需要阻止之前绑定的点击事件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .father {
      width: 100%;
      display: flex;
    }
    .child {
      width: 100px;
      height: 100px;
      background-color: aquamarine;
      margin: 10px;
    }
  </style>
</head>
<body>
  <div class="father">
    <div class="child">1
      <div class="bady-one">1-1
        <div class="yang-two">1-1-1</div>
      </div>
    </div>
    <div class="child">2
      <div class="bady-one out-box">2-1
        <div class="yang-two">2-1-1</div>
      </div>
    </div>
    <div class="child">3
      <div class="bady-one">3-1
        <div class="yang-two">3-1-1</div>
      </div>
    </div>
  </div>
  <script>
    // 示例:默认给每个child元素绑定一个点击事件,现在如果class名包含out-box的元素需要阻止之前绑定的点击事件
    const childElements = document.querySelectorAll('.child')

    childElements.forEach(el => {
      el.addEventListener('click', () => {
        console.log('child点击事件')
      })
    }) // 默认第三个参数为false,在冒泡阶段执行
  </script>

  <script>
	// 处理需求:在捕获阶段找到class名包含out-box的元素,并阻止冒泡
    const fatherElement = document.querySelector('.father')
    fatherElement.addEventListener('click', (el) => {
      const curentElement = el.target // 点击事件触发的元素,如果不是child元素,需要再找到它的class为child的父元素
      const parentElement = getParentElement(curentElement, 'child')
      if (curentElement.classList.toString().indexOf('child') !== -1 || parentElement) {
        if (curentElement?.querySelector('.out-box') || parentElement?.querySelector('.out-box')) {
          // console.log('点击事件')
          el.preventDefault() // 阻止默认行为
          el.stopPropagation() // 阻止冒泡
        }
      }
    }, true) // true点击事件在捕获阶段执行


    // 获取一个元素指定的父元素,使用元素的parentElement属性和while循环向上遍历DOM树,直到找到指定的父元素为止
    function getParentElement(target, className) {
      let parent = target.parentElement
      while (parent) {
        if (parent.classList.toString().indexOf(className) !== -1) {
          return parent
        }
        parent = parent.parentElement
      }
      return null
    }
  </script>
</body>
</html>

DOM事件流
在这里插入图片描述
事件触发经典案例
在这里插入图片描述

解析:前面提到的DOM事件流的执行顺序是先捕获再冒泡,所以dom事件流从外向内捕获过程就是grandma -> monther -> daughter -> baby,而只有monther和daughter设置了useCapture = true,所以在捕获阶段就先将事件处理了,而grandma和baby并未设置useCapture = true,默认是false,而我们又是点击的baby所以首先会先处理baby目标事件,然后再通过冒泡到grandma事件。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值