JS事件冒泡与JS事件代理(事件委托)

JS事件冒泡与JS事件代理(事件委托)

  • 1、事件冒泡
    • 1.1 概念
    • 1.2 要是不给子元素添加具体的oncilck处理方法,也能冒泡么?
    • 1.3 子元素触发的事件冒泡会触发父元素所有的事件么?还是触发对应的事件?
    • 1.4 那么我们应该如何组织这讨厌的事件冒泡机制呢?
  • 2、事件委托(事件代理)
    • 2.1 概念
    • 2.2 for循环遍历给每个li添加事件
    • 2.3 利用事件代理给li添加事件

1、事件冒泡

1.1 概念

通俗来讲,当触发(点击或者触摸之类的做法)有父元素的子元素的时候,事件会从事件源(被点击的子元素)开始逐级向上传播,触发父级元素的点击事件,一直会传到window。如果在某一层想要中止冒泡,使用 event.stopPropagation() 。下面见详细的代码:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    #parent {
      width: 400px;
      height: 400px;
      background-color: blue;
      display: flex;
      justify-content: center;
      align-items: center;
    }

    #child {
      width: 200px;
      height: 200px;
      background-color: brown;
    }
  </style>

</head>

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

  <script>

    let parent = document.getElementById('parent')
    parent.onclick = function () {
      console.log('parent')
    }

    let child = document.getElementById('child')
    child.onclick = function () {
      console.log('child')
    }

  </script>
</body>

</html>

JS事件冒泡与JS事件代理(事件委托)_第1张图片
我们可以发现,当点击红色区域(子元素)的时候,父级元素的click事件也被触发了。

接下来看两个示例:

1.2 要是不给子元素添加具体的oncilck处理方法,也能冒泡么?

<script>

    // let parent = document.getElementById('parent')
    // parent.onclick = function () {
      // console.log('parent')
    // }

    let child = document.getElementById('child')
    child.onclick = function () {
      console.log('child')
    }

  </script>

效果如下:
JS事件冒泡与JS事件代理(事件委托)_第2张图片
子元素在没有定义具体的click处理函数的时候仍然可以冒泡,触发父级元素的click事件。

1.3 子元素触发的事件冒泡会触发父元素所有的事件么?还是触发对应的事件?

 <script>

    let parent = document.getElementById('parent')
    parent.onkeydown = function () {
      console.log('parent')
    }

    let child = document.getElementById('child')
    child.onclick = function () {
      console.log('child')
    }

  </script>

结果如下:
JS事件冒泡与JS事件代理(事件委托)_第3张图片
我们发现只有相应的事件会发生事件冒泡,不相关的事件不受影响(注意由于click为鼠标的点击,所以同样会触发mousedown与mouseup等相关事件,同时发生冒泡!)

1.4 那么我们应该如何组织这讨厌的事件冒泡机制呢?

很简单,在事件触发时,会传入一个相应的event对象,其中有一个stopPropagation()方法可以阻止事件冒泡(IE中为cancleBubble=true),以下是详细代码:

 <script>
    let parent = document.getElementById('parent')
    parent.onclick = function () {
      console.log('parent')
    }

    let child = document.getElementById('child')
    child.onclick = function (ev) {
      var e = ev || window.event
      // console.log(e)
      console.log('child')
      stopPropagation(e)
    }
    function stopPropagation (e) {
      if (e.stopPropagation) {
        e.stopPropagation()
      } else {
        e.cancelBubble = true
      }
    }
  </script>

结果如下:
JS事件冒泡与JS事件代理(事件委托)_第4张图片
可以通过运行结果来看,事件冒泡成功被阻止了。

看到这里,相信小伙伴们可能会觉得事件冒泡很麻烦,还需要写个事件阻止冒泡行为。但凡事都有双刃剑,事件冒泡同时给我们带来的还有事件委托这一减少DOM操作的神器。

2、事件委托(事件代理)

2.1 概念

事件委托,首先按字面的意思就能看你出来,是将事件交由别人来执行,再联想到上面讲的事件冒泡,是不是想到了?对,就是将子元素的事件通过冒泡的形式交由父元素来执行。下面经过详细的例子来说明事件委托:

2.2 for循环遍历给每个li添加事件

在开发的时候可能会遇到这种情况:如给ul下的每个li都加一个事件,你可能会通过遍历来给每个栏目添加事件:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

</head>

<body>
  <ul id="parentUl">
    <li>我是子元素</li>
    <li>我是子元素</li>
    <li>我是子元素</li>
  </ul>

  <script>

    var ul = document.getElementById('parentUl'),
      li = ul.getElementsByTagName('li')
    for (var i = 0; i < li.length; i++) {
      li[i].onclick = function () {
        alert(this.innerHTML)
      }
    }
  </script>
</body>

</html>

JS事件冒泡与JS事件代理(事件委托)_第5张图片
这种方式来添加事件固然简单,但是需要多次操作DOM,如果有100、1000个同级的元素需要添加事件,这种方式就不可取了。

2.3 利用事件代理给li添加事件

事件委托是利用事件的冒泡原理来实现的,比如我们平时在给ul中的li添加事件的时候,我们都是通过for循环一个个添加,如果li很多个的话,其实就有点占内存了,这个时候可以用 事件代理来优化性能,

<!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>Document</title>
</head>

<body>
  <ul id='ulid' onclick='clickFunc()'>
    <li>1个li</li>
    <li>2个li</li>
    <li>3个li</li>
    <li>4个li</li>
    <li>5个li</li>
  </ul>

  <script>
    function clickFunc (ev) {
      var ev = ev || window.event
      console.log(ev)
      var oLi = ev.srcElement || ev.target
      if (oLi.nodeName.toLowerCase() == 'li') {
        alert(oLi.innerText)
      }

    }

  </script>
</body>

</html>

结果如下:
JS事件冒泡与JS事件代理(事件委托)_第6张图片

你可能感兴趣的:(JavaScript,javascript,css,css3)