JS中的事件流及DOM0、DOM2简介

本文介绍了JavaScript中的事件流概念,包括DOM0级和DOM2级事件处理方式。DOM0级事件仅支持冒泡阶段,同一事件后面的绑定会覆盖前面的。DOM2级事件允许捕获和冒泡阶段,并可以通过addEventListener添加事件,同时支持移除事件处理函数。此外,文章还探讨了事件模型中的冒泡和捕获阶段,以及事件委托和阻止冒泡的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DOM0级事件和DOM2级事件

事件就是用户或浏览器自身执行的某种操作,如click、load、mouseover等,都是事件的名字,而响应某个事件的函数就被称为事件处理程序。

事件过程
当用户操作浏览器的时候,浏览器一直监听者用户的操作,会触发若干个事件,同时检测事件是否有赋值某个事件函数,如果未赋值为null , 如果某个事件上有事件函数,那么就被执行;
btn.onclick // ==null == 未赋值
btn.haha // == undefined == 自定义的


一、0级DOM

0级DOM分为两种

1、在标签内写onclick事件

2、在JS写οnclick=function(){}函数

  • 解除事件将某个元素的事件赋值为null
    ele.事件 = null
// 1、行内
<button id="btn" onclick="alert(1)">按钮</button>

// 2、元素,on事件名 = 函数
document.getElementById("btn")..onclick = function(){
    alert(1);       
}

0级DOM事件的特点

  • 1、DOM0级事件只能触发事件冒泡阶段不能触发事件捕获阶段。
box2.onclick = function(){
	alert("我是box2");
}
box3.onclick = function(){
	alert("我是box3");
}

不管怎么改变事件的绑定顺序,不影响弹出框。box2–>box3,因为DOM0只能触发事件冒泡不能触发事件捕获。

2、同一元素绑定相同的事件,后面的会覆盖前面的。

点击btn 只会弹出2,因为on**方法相当于给元素添加属性。后面写的会覆盖先写的。

///1、覆盖事件演示
btn.onclick = function(){
   alert('hello');       
}

btn.onclick = function(){
   alert('hello,我是真的');
   btn.onclick = null; //  只弹一次
        }
//此时只会弹出‘hello,我是真的’,因为下边把上边的覆盖了;

// 2、如果需要添加多个事件,那么可以通过一遍这种形式操作
btn.onclick = function(){
          fn();
          fn2();      
      };
      
function fn(){
      alert(1)
  };
function fn2(){
     alert(2)
 };

3、this指的是事件流传播到这个元素,就是元素本身
4、DOM0捕获不到捕获阶段,只有冒泡阶段.

二、DOM2级事件处理

监听方法

绑定事件的方法
ele.addEventListener()

解除事件的方法
ele.removeEventListener()

有三个参数

  • 第一个参数,事件名(如click、mouseover等);
  • 第二个参数,事件函数;
  • 第三个参数,如果是true则表示在捕获阶段调用,为false表示在冒泡

ele.addEventListener(‘不带on的事件名’,函数,是否捕获)
ele.removeEventListener(‘不带on的事件名’,有名函数(和绑定函数一个地址),是否捕获);

//第一种清除方式--- 有效
btn.addEventListener('click', function hh() {
            alert(2);
            btn.removeEventListener('click', hh);
        });

//第二种清除方式  ---无效,虽然执行内容一样,但是地址改变了,非同一地址
let cc = c.bind(this) 
btn.addEventListener('click',c);

function c(){
   alert(1);
   btn.removeEventListener('click',cc);
}

请注意此时DOM2清除的必须是有名函数,并且第一样;

DOM2的特点

1、同一个元素绑定相同的事件,后面的不会覆盖前面的。
因为DOM2级事件绑定不是给元素添加属性是直接添加的事件。等同于给一个元素绑定了多个事件。
2、在DOM2级事件处理中通过addEventListener()添加的匿名函数无法移除,只能清除有名函数;
3、2级DOM包含3个事件:事件捕获阶段、处于目标阶段和事件冒泡阶段;

事件模型(事件流)

事件模型预告

只有2级DOM包含3个事件:事件捕获阶段、处于目标阶段和事件冒泡阶段;
在点击按钮的时候,不但弹出了"我是box" 也弹出我是 “我是btn” ,这是因为元素的事件基本上都遵循事件模型机制。

<body>
    <div id="box">我是box
        <button id="btn">我是按钮</button>
    </div>
<script>
  box.onclick = function(){
        alert('我是box');
    }

    btn.onclick = function(){
        alert('我是btn');
    }
</script>

点击a后capturing(捕捉)阶段事件传播会 从 document-> div ->button,然后发生在button,最后bubbling(冒泡)阶段事件传播会从button->div ->document

事件模型

从捕获阶段 到 目标阶段 再到 冒泡阶段 的过程称为事件流。
先执行捕获再执行冒泡。

在这里插入图片描述

1.冒泡阶段(常用)

  • 从目标点由下而上 直到window ,叫做冒泡阶段 。
  • 事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象。
  • 在这个过程中,如果上级和下级同理有祖先关系,绑定同一事件函数 先触发目标 再触发目标的上级;

2.捕获阶段

  • 从window 到 目标点的阶段 ,叫捕获阶段
  • 在捕获的过程中,如果上级和下级(祖先级关系)绑定同一事件函数,那么先触发上级的在触发下级的;

ps : 如果事件绑定的是目标元素,那么是按照绑定事件函数的先后顺序来依次执行(跟捕获冒泡没关系)

小例子

做做小练习,看看他们的执行顺序,看看自己是否真的理解 事件模型;

 function fn(){alert('btn1');}
    
    btn.addEventListener('click',fn,true);
    btn.addEventListener('click',function(){alert(1);},true);
    btn.addEventListener('click',function(){alert(2);},true);
    box1.addEventListener('click',function(){alert('red');});
    btn.addEventListener('click',fn,true); 
    box3.addEventListener('click',function(){alert('yellow');},true);
    box2.addEventListener('click',function(){alert('blue');},true);
    box2.addEventListener('click',function(){ alert('green');});
    btn.addEventListener('click',function(){alert('btn捕获');},true);
    btn.addEventListener('click',fn,false);
    btn.addEventListener('click',function(){alert('btn冒泡');});
    btn.addEventListener('click',function(){alert('btn冒泡2');});

冒泡的好处— 事件委托

  • 如果一个父节点内含有多个子节点,并且每个子节点都存在同一事件类型(如onclick)。我们可以为其父代设置一个事件处理器(onclick),来避免为其每个子代设置一个事件处理器,降低内存,提高性能。
<body>
    <ul id="ul">
        <li></li>
        <li></li>
        <li></li>
        <li></li>
    </ul>
    <script>
//之前的方式  --- 需要循环,消耗性能
        const lis = document.querySelectorAll('li');
        lis.forEach(e => {
            e.onclick = function () {
                this.style.background = 'green';
            }
        });
//冒泡--事件委托
        ul.onclick = function (ev) {
            if (ev.target.tagName === 'LI') {
                        ev.target.style.background = 'green';
            }
        }
    </script>
    // ev.target  目标点(事件源)
//   在嵌套关系中,给上层元素绑定事件,可以通过事件源查到事件触发的对象(元素)
//   tagName 查看标签名  注意:大写

冒泡的坏处 — 阻止冒泡

背景:

事件函数中的第一个参数,默认为事件对象。

  • 事件对象:当用户触发某个事件的时候,记录用户操作页面的一些细节信息,也就会出现,自己冒泡触发祖先级的同一事件;

    event
    chrome/IE window中都有一个event
    FF中是没有event对象的 *

阻止冒泡: (目的是为了不让自己冒泡触发祖先级的同一事件)

ev.cancelBubble = true;它不是一个标准,但是所有浏览器都支持;
ev.stopPropagation();它是标准,但是在低版本IE下是不兼容的;

如下:

<body>
    <button id="btn">打开</button>
    <div id="box"></div>
<script>

    let onoff = true;
    btn.onclick = function(ev){
        if(onoff){
            box.style.display = 'block';
            btn.innerHTML = '隐藏'
        }else{
            box.style.display = 'none';
            btn.innerHTML = '打开'
        }
        onoff = !onoff;
        ev.cancelBubble = true;
        // ev.stopPropagation();
    }

    document.onclick = function(){
        box.style.display = 'none';
        onoff = true;
        btn.innerHTML = '打开'
    } 

点击button的时候,也会触发document使box.style.display = ‘none’;
那么我们可以在目标源阻止ev.cancelBubble = true; /ev.stopPropagation();
阻止自己冒泡触发祖先级的同一事件;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值