JavaScript——事件捕获和事件冒泡

目录

前言

事件捕获(event capturing)

事件冒泡(dubbed bubbling)

阻止事件捕获和事件冒泡


前言

在JavaScript中,我们将事件发生的顺序成为“事件流”,当我们触发某个事件时,会发生一系列的连锁反应。

但是,如果我们有几个嵌套的元素来处理同一个事件(如下图),到底哪个事件会先被触发呢?所以,我们需要理解事件传播顺序。

微软和网景这两个公司提出了两种不同的概念,分别是事件捕获和事件冒泡。

事件捕获是由微软公司提出的,当鼠标点击或触发DOM事件时(被触发DOM事件的这个元素被叫做事件源),浏览器会从根节点=>事件源(由外层到内层)进行事件传播。

事件冒泡是由网景公司提出的,它的传播顺序与事件捕获相反,是从事件源=>根节点(由内层到外层)进行事件传播。

我们现在使用DOM标准事件流的传播顺序的是W3C统一后的标准——先捕获后冒泡。即当出发DOM事件时,会先进行事件捕获,捕获到事件源之后通过事件传播进行事件冒泡。如下图。

我们还需要了解DOM事件流(event flow)存在三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。

简单了解过后,下面我们来看事件捕获和事件冒泡是如何出现的。

事件捕获(event capturing

事件捕获是由外到内的。在事件捕获阶段,事件会从 DOM 树的最外层开始,依次经过目标节点的各个父节点,并触发父节点上的事件,直至到达事件的目标节点。如下图。

上图的例子中,事件处理顺序是Window=>Document=>box1=>box2=>a。除此之外,我们还可以观察到:事件捕获只发生在被点击的元素或目标上,该事件不会传播到子元素

我们用到了addEventListener方法,在一般情况下,该方法只会用到两个参数,一个是需要绑定的事件,另一个是触发事件后要执行的函数,但是,addEventListener还可以传入第三个参数,该参数默认值是false,表示在事件冒泡阶段调用事件处理函数;如果该参数为true,则表示在事件捕获阶段调用处理函数。

JavaScript测试部分代码如下:

<script>

    window.addEventListener("click",()=>{

        console.log("Window");

    },true);

    document.addEventListener("click",()=>{

        console.log("Document");

    },true);

    document.querySelector("#box2").addEventListener("click",()=>{

        console.log("box2");

    },true);

    document.querySelector("#box1").addEventListener("click",()=>{

        console.log("box1");

    },true);

    document.querySelector("a").addEventListener("click",()=>{

        console.log("Click me");

    },true);

</script>

事件冒泡(dubbed bubbling

上面我们说了事件捕获,事件冒泡和事件捕获是完全相反的。事件冒泡是由内到外的,它是从目标节点开始,沿父节点依次向上,并触发父节点上的事件,直至文档根节点,就像水底的气泡一样,会一直向上。如下图。

上图的例子中,事件处理顺序是Window<=Document<=box1<=box2<=a

上面我们说到,addEventListener的第三个参数默认值是false,表示在事件冒泡阶段调用事件处理函数,这说明事件监听器默认监听冒泡事件。

JavaScript测试部分代码如下:

<script>

    window.addEventListener("click",()=>{

        console.log("Window");

    },false);

    document.addEventListener("click",()=>{

        console.log("Document");

    },false);

    document.querySelector("#box2").addEventListener("click",()=>{

        console.log("box2");

    },false);

    document.querySelector("#box1").addEventListener("click",()=>{

        console.log("box1");

    },false);

    document.querySelector("a").addEventListener("click",()=>{

        console.log("Click me");

    },false);

</script>

阻止事件捕获和事件冒泡

在我们了解事件捕获和事件冒泡后,难免会思考一个问题:如果我们在某个节点上绑定了一个事件,我们需要在点击时触发这个事件,但是由于事件冒泡,这个节点的事件被它的子元素触发了,我们应该怎么阻止这种情况发生呢?

我们可以使用stopPropagation()方法来阻止这种情况发生,它将阻止事件沿着DOM树向上或向下进一步传播。如下图。

JavaScript测试部分代码如下:

<script>

    window.addEventListener("click",(e)=>{

        console.log("Window");

        e.stopPropagation();

    },false);

    document.addEventListener("click",(e)=>{

        console.log("Document");

        e.stopPropagation();

    },false);

    document.querySelector("#box2").addEventListener("click",(e)=>{

        console.log("box2");

        e.stopPropagation();

    },false);

    document.querySelector("#box1").addEventListener("click",(e)=>{

        console.log("box1");

        e.stopPropagation();

    },false);

    document.querySelector("a").addEventListener("click",(e)=>{

        console.log("Click me");

        e.stopPropagation();

    },false);

</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值