# DOM事件传播机制

在学习传播机制前,我们需要先了解事件流模型

# 事件流

事件流描述的是从页面中接收事件的顺序

目前主要有三种模型
1. 事件冒泡:事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的元素
2. 事件捕获:不太具体的节点更早接收事件,而最具体的元素最后接收事件,和事件冒泡相反
3. DOM事件流:DOM2级事件规定事件流包括三个阶段,事件捕获阶段,处于目标阶段,事件冒泡阶段,首先发生的是事件捕获,为截取事件提供机会,然后是实际目标接收事件,最后是冒泡阶段
<!DOCTYPE html >
<html>
<head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <title>Test Page</title>
</head>
<body>
    <div>
        Click Here
    </div>
</body>
</html>

当点击div区域时,事件传播顺序:

# 1. 事件冒泡模型:

传播顺序:div --> body --> html --> Document

也就是说,click事件首先在<button>元素上发生,然后逐级向上传播。这就是事件冒泡。

# 2. 事件捕获模型:

传播顺序:Document --> html --> body --> div

# 3.DOM事件流

传播顺序:Document --> html --> body --> div --> body --> html --> Document

# 事件处理程序

# HTML内联方式

<input type="button" value="Click Here" onclick="alert('Clicked!');" />

缺点 1 存在加载顺序问题,如果事件处理程序在html代码之后加载,用户可能在事件处理程序还未加载完成时就点击按钮之类的触发事件,存在时间差问题 2 书写html代码和JavaScript代码紧密耦合,维护不方便

# JavaScript指定事件处理程序
<input id="btnClick" type="button" value="Click Here" />
<script type="text/javascript">
    var btnClick = document.getElementById('btnClick');
    btnClick.onclick = function showMessage() {
        conole.log('hello');
    };
    btnClick.onclick = function showMessage() {
        console.log('hi');
    };
</script>

优点:删除事件处理程序,只需把元素的onclick属性赋为null即可 缺点:会产生覆盖,某些场景下无法满足需求

# DOM2事件处理程序

DOM2级事件定义了两个方法用于处理指定和删除事件处理程序的操作: addEventListener、removeEventListener 所有的DOM节点都包含这两个方法,并且它们都接受三个参数:

  • 事件类型
  • 事件处理方法
  • 布尔参数,如果是true表示在捕获阶段调用事件处理程序,如果是false,则是在事件冒泡阶段处理
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
  <style>
    .container,
    .box,
    .target{
      border: 1px solid;
      padding: 10px;
    }  
  </style>
  <button id="btn">click</button>
  
  <div class="container">
    container
    <div class="box">
      box
      <div class="target">target</div>
    </div>
  </div>  
  <script>
    var container = document.querySelector('.container')
    var box = document.querySelector('.box')
    var target = document.querySelector('.target')
    container.addEventListener('click', function(){
      console.log('contianer click.. in 捕获阶段')
    }, true)
    box.addEventListener('click', function(){
      console.log('box click.. in 捕获阶段')
    }, true)
    target.addEventListener('click', function(){
      console.log('target click.. in 捕获阶段')
    }, true)
    container.addEventListener('click', function(){
      console.log('contianer click.. in 冒泡阶段')
    }, false)
    box.addEventListener('click', function(){
      console.log('box click.. in 冒泡阶段')
    }, false)
    target.addEventListener('click', function(){
      console.log('target click.. in 冒泡阶段')
    }, false)  
  </script> 
</body>
</html>

# 阻止事件传播

preventDefault():取消事件默认行为 stopPropagation():取消事件进一步捕获或冒泡 target:事件的目标元素

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
  <a href="http://jirengu.com">饥人谷</a>
  <script>
    var linka = document.querySelector('a');
    linka.addEventListener('click',function(){
       console.log(this.href);
       event.preventDefault();
    });
//   document.querySelector('a').onclick= function(e){
//     e.preventDefault()
//     console.log(this.href)
//     if(/jirengu.com/.test(this.href)){
//       location.href = this.href
//     }
//   }
  </script>  
</body>
</html>

阻止前

阻止后