事件源

在事件中,当前操作的那个元素是事件源。

事件流

事件流描述的是从页面接收事件的顺序。
DOM事件流三个阶段:

  • 事件捕获阶段
  • 处于目标阶段
  • 事件冒泡阶段

事件捕获

当鼠标点击或者触发dom事件时,浏览器会从根结点从外向内进行传播。可以理解为,点击了子元素,如果父元素通过事件捕获方式创建了相应的事件,就会先触发父元素绑定的事件。

事件冒泡

跟捕获相反,是从目标元素开始,从内向外进行事件传播。
我们平时用的事件绑定就是利用的事件冒泡原理。

DOM事件流触发顺序

image (4) (1).png
1-5是捕获阶段,5-6是目标阶段,6-10是冒泡阶段。
结论:

  • 当容器元素及嵌套元素既处于捕获阶段又处于冒泡阶段调用事件处理程序时,事件按DOM事件流的顺序调用事件处理程序。如上图所示。
  • 当事件处于目标阶段时,事件调用顺序决定于绑定事件的顺序。
  • DOM0方式绑定的事件在冒泡时触发,取决于书写绑定的顺序

    1. <div id="outerBox" style="width: 200px;height: 200px;background: red;">
    2. <div id="innerBox" style="width: 100px;height: 100px;background: orange;">
    3. <div id="targetBox" style="width: 50px;height: 50px;background: blue;"></div>
    4. </div>
    5. <div>
    6. <script>
    7. const outerBox = document.querySelector('#outerBox');
    8. const innerBox = document.querySelector('#innerBox');
    9. const targetBox = document.querySelector('#targetBox')
    10. outerBox.onclick = function(){
    11. console.log('outerBox','click')
    12. }
    13. outerBox.addEventListener('click',function(){
    14. console.log('outerBox','事件冒泡')
    15. },false);
    16. innerBox.addEventListener('click',function(){
    17. console.log('innerBox','事件冒泡')
    18. },false);
    19. targetBox.addEventListener('click',function(){
    20. console.log('targetBox','事件冒泡')
    21. },false)
    22. outerBox.addEventListener('click',function(){
    23. console.log('outerBox','事件捕获')
    24. },true);
    25. innerBox.addEventListener('click',function(){
    26. console.log('innerBox','事件捕获')
    27. },true);
    28. targetBox.addEventListener('click',function(){
    29. console.log('targetBox','事件捕获')
    30. },true)
    31. targetBox.onclick = function(){
    32. console.log('targetBox','click')
    33. }
    34. </script>

    上述点击触发顺序

    • outerBox 事件捕获 //先进入捕获阶段,触发捕获事件
    • innerBox 事件捕获
    • targetBox 事件冒泡 //进入目标阶段,因为冒泡事件写在了捕获事件前面,所以先触发冒泡事件,捕获事件,和click同理,按照绑定的先后顺序逐次出发
    • targetBox 事件捕获
    • targetBox click
    • innerBox 事件冒泡 //进入冒泡阶段,此时伴随click事件,其先后顺序同样取决于绑定顺序
    • outerBox click
    • outerBox 事件冒泡

更正:在 Chrome 89.0.4363.0 以及之后版本中,目标元素的触发事件顺序不再按照注册顺序触发!而是按照先捕获再冒泡的形式依次执行!
他喵的好气,竟然更新了;但是我的chrome版本更新不到89.xx以上,也没有验证到。

事件对象

触发dom上的某个事件时会产生一个事件对象,里面包含着所有和事件有关的信息。

  1. outerBox.addEventListener('click',clickEvent)
  2. function clickEvent(e){
  3. console.log( e )
  4. console.log(e.currentTarget)
  5. console.log(e.target)
  6. }

e里的信息如下图所示:
image.png
常用的属性如下:

  • target 事件的目标 (对于目标)
  • currentTarget 事件处理程序当前正在处理事件的那个元素(始终等于this
  • preventDefault 取消事件默认行为,比如链接的跳转
  • stopPropagation 取消事件冒泡

target,currentTarget直接在事件对象里看不到,但是可以点出来,如下
对于目标阶段,target,currentTarget,this 完全一样
image.png

阻止事件冒泡

  1. targetBox.addEventListener('click',function(e){
  2. console.log('targetBox','事件冒泡')
  3. e.stopPropagation()
  4. },false)

如上,外层的innerBox,outerBox,即使绑定了事件,在点击targetBox时也不会被触发了。
targetBox在冒泡,捕获,或者DOM0 onclick方式阻止都可。

  1. IE8以下的兼容写法
  2. function stopPropagate(e){
  3. var event = e || window.event;
  4. if(event.stopPropagation){
  5. event.stopPropagation();
  6. }else if(event.cancelBubble){ //IE
  7. event.cancelBubble = true;
  8. }
  9. }

取消默认行为

  1. //兼容写法
  2. function preventDef(e){
  3. var g = e || window.event;
  4. if(g.preventDefault){
  5. g.preventDefault();
  6. }else if(g.returnValue){
  7. g.returnValue = false;
  8. }
  9. return false;
  10. }