JavaScript基础学习——事件的冒泡、捕获、委托

1、事件流

事件流指的是从页面中接收事件的顺序。分为冒泡流和捕获流。

DOM二级事件规定事件流包括三个阶段:
1、事件捕获阶段
2、处于目标阶段
3、事件冒泡阶段

DOM在触发事件后,会经历事件捕获和事件冒泡两个最重要阶段。

2、事件冒泡

由最里层向最外层触发事件的过程,叫事件冒泡。

例1:事件冒泡测试

<!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>
  <style>
    .parent {
      width: 300px;
      height: 200px;
      background-color: #f00;
    }

    .child {
      width: 200px;
      height: 100px;
      background-color: #ff0;
    }
  </style>
</head>

<body>
  <div class="parent">
    <div class="child">Please click me!</div>
  </div>
</body>
<script>
  var parent = document.getElementsByClassName('parent')[0];
  var child = document.getElementsByClassName('child')[0];

  child.addEventListener('click', function () {
    console.log('child')
  }, false)  // false:表示事件冒泡  true:表示事件捕获

  parent.addEventListener('click', function () {
    console.log('parent')
  }, false)

  document.body.addEventListener('click', function () {
    console.log('body')
  }, false)

  document.addEventListener('click', function () {
    console.log('document')
  }, false)

  window.addEventListener('click', function () {
    console.log('window')
  }, false)
</script>

</html>

如果单击了div,事件会按child->parent->body->document->window顺序触发,相当于逐级向上触发,这种情况叫事件冒泡。

 

3、事件捕获

由最外层向最里层触发事件的过程,叫事件捕获。

语法:DOM.addEventListener('事件名',callback,true)

<!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>
<style>
  .parent {
    width: 300px;
    height: 200px;
    background-color: #f00;
  }

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

<body>
  <div class="parent">
    <div class="child">Please click me!</div>
  </div>
</body>
<script>
  var parent = document.getElementsByClassName('parent')[0];
  var child = document.getElementsByClassName('child')[0];

  child.addEventListener('click', function () {
    console.log('child')
  }, true)  // false:表示事件冒泡  true:表示事件捕获

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

  document.body.addEventListener('click', function () {
    console.log('body')
  }, true)

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

  window.addEventListener('click', function () {
    console.log('window')
  }, true)
</script>

</html>

由最外层向最里层触发事件的过程,叫事件捕获,这个过程与事件冒泡的过程是相反的,如果想要把事件冒泡改为事件捕获,要用addEventListener去写事件监听,不要直接用onXXX事件去写,将触发的子元素的父元素以上的元素的事件后用true实现。

 

4、阻止冒泡

var e = e || window.event;
e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true; // 阻止事件冒泡兼容写法

e.stopPropagation(); // 不考虑兼容的写法

例3:测试阻止冒泡

<!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>
  <style>
    .parent {
      width: 300px;
      height: 200px;
      background-color: #f00;
    }

    .child {
      width: 200px;
      height: 100px;
      background-color: #ff0;
    }
  </style>
</head>

<body>
  <div class="parent">
    <div class="child">Please click me!</div>
  </div>
</body>
<script>
  var parent = document.getElementsByClassName('parent')[0];
  var child = document.getElementsByClassName('child')[0];

  child.addEventListener('click', function (e) {
    var e = e || window.event;
    e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true; // 阻止事件冒泡兼容写法
    console.log('child')
  }, false)

  parent.addEventListener('click', function (e) {
    e.stopPropagation(); // 不考虑兼容的写法
    console.log('parent')
  }, false)

  document.body.addEventListener('click', function () {
    console.log('body')
  }, false)

  document.addEventListener('click', function () {
    console.log('document')
  }, false)

  window.addEventListener('click', function () {
    console.log('window')
  }, false)
</script>

</html>

5.事件委托

将所有子元素的事件写到(委托)父元素上,这样的过程叫事件委托。

使用场景:
1、将多个子元素的事件委托给父元素完成(基于性能优化的考虑)
2、在动态加进来元素上绑定事件

例4:测试事件委托

<!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 class="list">
    <li>li01</li>
    <li>li02</li>
    <li>li03</li>
    <li>li04</li>
    <li>li05</li>
  </ul>
</body>
<script src="event.js"></script>
<script>
  var lis = document.getElementsByClassName('list')[0]

  eventDeal.addHandler(lis, 'click', function (event) {
    //获取事件对象
    event = eventDeal.getEvent(event)

    //获取目标对象
    var target = eventDeal.getTarget(event)

    target.style.color = 'red'
    target.innerHTML += 'aaaa'
  })
</script>

</html>

 event.js中的代码

var eventDeal = {
  //event对象兼容处理
  getEvent: function (event) {
    return event || window.event
  },

  //目标对象兼容处理
  getTarget: function (event) {
    return event.target || event.srcElement
  },

  //绑定事件兼容处理
  addHandler: function (element, type, handler) {
    if (element.addEventListener) {
      element.addEventListener(type, handler, false)
    } else if (element.attachEvent) {//兼容IE低版本
      element.attachEvent('on' + type, handler)
    } else {
      element['on' + type] = handler
    }
  }
}

 

上一篇:Java常用类之Properties类


下一篇:Javascript面向对象基础 - 事件篇