# 事件触发三阶段

  • window 往事件触发处传播,遇到注册的捕获事件会触发
  • 传播到事件触发处时触发注册的事件
  • 从事件触发处往 window 传播,遇到注册的冒泡事件会触发 事件触发一般来说会按照上面的顺序进行,但是也有特例,如果给一个 body 中的子节点同时注册冒泡和捕获事件,事件触发会按照注册的顺序执行。
// 以下会先打印冒泡然后是捕获
node.addEventListener(
  'click',
  event => {
    console.log('冒泡')
  },
  false
)
node.addEventListener(
  'click',
  event => {
    console.log('捕获 ')
  },
  true
)

# 冒泡和捕获

<!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>capture</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
  <style type="text/css">
    div {
      width: 400px;
    }

    .pinkBorder {
      border: 1px solid;
      border-color: blue;
    }
  </style>
</head>

<body>
  <!-- 根据冒泡原则,点击id4时,正常情况应该按序弹出id4,id3,id2,id1
  但因为id1,id2配置了.capture, 所以id1,id2这两个变成了捕获事件, 优先触发,
 于是先执行id1,id2捕获, 再执行id4,id3冒泡, 最终按序弹出id1,id2,id4,id3 -->
  <div id="app">
    <div id="id1" class='pinkBorder' v-on:click.capture="doit">
      id1
      <div id="id2" class='pinkBorder' v-on:click.capture="doit">
        id2
        <div id="id3" class='pinkBorder' v-on:click="doit">
          id3
          <div id="id4" class='pinkBorder' v-on:click="doit">
            id4(点我最终按序弹出id1,id2,id4,id3)
          </div>
        </div>
      </div>
    </div>

  </div>

</body>
<script>

  var app = new Vue({
    el: "#app",
    data: {
      id: ''
    },
    methods: {
      doit: function () {
        this.id = event.currentTarget.id;
        alert(this.id)
      }
    }
  })

</script>

</html>
id1
id2
id3
id4(点我最终按序弹出id1,id2,id4,id3)
<!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>self</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
  <style type="text/css">
    div {
      width: 400px;
    }

    .pinkBorder {
      border: 1px solid;
      border-color: green;
    }
  </style>
</head>

<body>

  <!-- 根据冒泡原则,点击id4时,正常情况应该按序弹出id4,id3,id2,id1
但因为id2配置了.self,检测到不是自身,所以冒泡过程会跳过id2,最终按序弹出id4,id3,id1 -->
  <div id="content">
    <div id="id1" class='pinkBorder' v-on:click="doit">
      id1
      <div id="id2" class='pinkBorder' v-on:click.self="doit">
        id2
        <div id="id3" class='pinkBorder' v-on:click="doit">
          id3
          <div id="id4" class='pinkBorder' v-on:click="doit">
            id4(点我按序弹出id4,id3,id1)

          </div>
        </div>
      </div>
    </div>
  </div>

</body>
<script>

  var content = new Vue({
    el: "#content",
    data: {
      id: ''
    },
    methods: {
      doit: function () {
        this.id = event.currentTarget.id;
        alert(this.id)
      }
    }
  })

</script>

</html>
id1
id2
id3
id4(点我按序弹出id4,id3,id1)
<!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>stop</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
  <style type="text/css">
    div {
      width: 400px;
    }

    .pinkBorder {
      border: 1px solid;
      border-color: green;
    }
  </style>
</head>

<body>
    <!-- https://cn.vuejs.org/v2/guide/events.html#事件修饰符 -->
  <!-- 根据冒泡原则,点击id4时,正常情况应该按序弹出id4,id3,id2,id1
但因为id2配置了.stop,所以冒泡事件在id2之后终止,最终按序弹出id4,id3,id2 -->
  <div id="content">
    <div id="id1" class='pinkBorder' v-on:click="doit">
      id1
      <div id="id2" class='pinkBorder' v-on:click.stop="doit">
        id2 (v-on:click.stop)
        <div id="id3" class='pinkBorder' v-on:click="doit">
          id3
          <div id="id4" class='pinkBorder' v-on:click="doit">
            id4(点我按序弹出id4,id3,id2 )
          </div>
        </div>
      </div>
    </div>
  </div>

</body>
<script>

  var content = new Vue({
    el: "#content",
    data: {
      id: ''
    },
    methods: {
      doit: function () {
        this.id = event.currentTarget.id;
        alert(this.id)
      }
    }
  })
</script>

</html>

# event.stopPropagation

阻止捕获和冒泡阶段中当前事件的进一步传播

# event.stopImmediatePropagation()

阻止事件冒泡并且 阻止该元素上同事件类型的监听器被触发 【除了停止事件继续捕捉或冒泡传递外,也阻止事件被传入同元素中注册的其它相同事件类型监听器。

# 实际应用

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<title></title>
		<style>
			#k1{
				width:300px;
				height:300px;
				background: green;
			}
			#k2{
				width:200px;
				height:200px;
				background: orange;
			}
			#k3{
				width:100px;
				height:100px;
				background: red;
			}
		</style>
	</head>
	<body>
			<div id="k1">
				<div id="k2">
					<div id="k3"></div>
				</div>
			</div>
	</body>
</html>
<script type="text/javascript">
	var k1=document.getElementById("k1");
	var k2=document.getElementById("k2");
	var k3=document.getElementById("k3");
	k1.addEventListener("click",function(e){
		console.log(11)
	})
	k2.addEventListener("click",function(e){
		console.log(21)
	})
	k3.addEventListener("click",function(e){
		console.log(31)
	})
	k1.onclick=function(e){
		console.log(1)
	}
	k2.onclick=function(e){
		var ev=e||window.event
		console.log(2)
	}
	k3.onclick=function(e){
		console.log(3)
	}
	k1.addEventListener("click",function(e){
		console.log(12)
	},true)
	k2.addEventListener("click",function(e){
		console.log(22)
	},true)
	k3.addEventListener("click",function(e){
		console.log(32)
	},true)
</script>

DANGER

先捕获再冒泡(√) 如果是同元素,则哪个方法写在前,就先执行哪个 ??? [2021-05-27:浏览器版本不一样,结果并不和上一致,同种元素多事件,尽量不要写出这种情况][2023-07-22:而且不同的浏览器除了顺序结果不一致,甚至结论也不一致,完全没必要探讨这些]

最后更新: 7/23/2023, 8:07:02 AM