react 深入了解react合成事件底层原理,原生事件中阻止冒泡是否会阻塞合成事件?一


风晓
风晓 2024-01-01 07:06:42 50400 赞同 0 反对 0
分类: 资源
本篇文章就来着重介绍react中的合成事件,在文章开始之前我们先罗列部分问题:
  • 了解原生事件监听机制吗?为什么需要事件代理?
  • react如何实现的合成事件?这么做的好处是什么?
  • 合成事件与原生事件执行先后顺序。
  • 合成事件阻止冒泡会阻塞原生事件吗?原生事件阻止冒泡会阻塞合成事件吗?

在文章开始前,大家可以先自行思考这些问题,假设这些在面试中遇到,你能回答多少呢?那么本文开始。

贰 ❀ 从原生事件说起

虽然本文的核心重点是介绍react的合成事件,但文章开头既然给了合成事件与原生事件相关对比问题,因此了解原生事件是有必要的,考虑到可能有同学对此类知识存在遗忘,这里做个简单复习。

首先让我们复习下事件监听api addEventListener,基本语法如下:

element.addEventListener(event, function, useCapture);

其中element表示你需要监听的dom元素;event表示监听的事件类型,比如onclick,onblurfunction表示触发事件后的回调,你需要做什么都可以写在这里;useCapture是一个布尔值,表示是否开启捕获阶段,默认false

以如下代码结构为例,当我们点击span时,必然会经历过捕获阶段----》目标阶段----》冒泡阶段

我们用一个例子复习这个过程:

<div id="div">
    我是div
    <p id="p">
        我是p
        <span id="span">我是span</span>
    </p>
</div>
const div = document.querySelector("#div");
const p = document.querySelector("#p");
const span = document.querySelector("#span");
// 捕获阶段,这里将useCapture设置为true
div.addEventListener("click",()=>console.log("捕获阶段--div"),true);
p.addEventListener("click",()=>console.log("捕获阶段--p"),true);
// 目标阶段
span.addEventListener("click",()=>console.log("目标阶段--span"));
// 冒泡阶段,useCapture默认false,不写了
div.addEventListener("click",()=>console.log("捕获阶段--div"));
p.addEventListener("click",()=>console.log("捕获阶段--p"));

既然提到了事件监听,那么有三个API就不得不提了,它们分别是event.preventDefaultevent.stopPropagationevent.stopImmediatePropagation。让我们先聊聊stopPropagation,此方法一般用于阻止冒泡,比如父子都绑定了点击事件,但点击子时我不希望父在冒泡阶段也被触发,因此通过在子的事件回调中添加此方法能做到这一点,修改上述例子中目标阶段的代码为:

span.addEventListener("click", (e) => {
    e.stopPropagation();
    console.log("目标阶段--span")
});

此时点击span会发现只会输出span,而冒泡阶段的divp都被阻止执行了。

关于event.preventDefault,此方法常用于阻止元素默认行为,比如点击a标签除了执行我们绑定的click事件外,它还会执行a标签默认的跳转。再或者form表达点击提交会将form的值传递给action指定地址并刷新页面,像这类行为我们均可以通过preventDefault阻止。

在介绍stopImmediatePropagation之前,我们需要知道事件监听相对于普通事件绑定的一大好处是,事件监听支持为同一dom监听多个行为,但如果是普通的事件绑定后者会覆盖前者:

span.onclick = ()=>console.log('事件绑定-1');
// 后绑定的事件会覆盖前面的绑定
span.onclick = ()=>console.log('事件绑定-2');
// 事件监听就不会存在覆盖,下面2个都会执行
span.addEventListener("click", (e) => {
    console.log("事件监听-1")
});
span.addEventListener("click", (e) => {
    console.log("事件监听-2")
});

那既然事件监听支持为同一dom绑定多个,我在执行了某个监听后,需要将其它监听都阻止掉怎么办?此时就轮到stopImmediatePropagation出场立大功了,看个例子:

// 捕获阶段
div.addEventListener("click", () => console.log("捕获阶段--div-1"), true);
div.addEventListener("click", () => console.log("捕获阶段--div-2"), true);
p.addEventListener("click", () => console.log("捕获阶段--p-1"), true);
p.addEventListener("click", () => console.log("捕获阶段--p-2"), true);
// 目标阶段
span.addEventListener("click", (e) => {
    e.stopImmediatePropagation();
    console.log("目标阶段---span-1")
});
span.addEventListener("click", (e) => {
    console.log("目标阶段---span-2")
});
// 冒泡阶段
div.addEventListener("click", () => console.log("捕获阶段--div-1"));
div.addEventListener("click", () => console.log("捕获阶段--div-2"));
p.addEventListener("click", () => console.log("捕获阶段--p-1"));
p.addEventListener("click", () => console.log("捕获阶段--p-2"));

可以看到stopImmediatePropagation同样会阻止事件冒泡,但除此之外,它还会阻止同一dom身上的其它事件执行。

那么聊完事件监听,什么是事件代理?在现实生活中,我们网购到公司的快递大部分都会由前台代签收,而不是分别送到我们每个人手上,此时前台就相当于做了一个代理的事情,原本需要不同的多个人分别签收的行为,统一与前台代理处理。

映射到代码中,假设有ul>li的结构,我们希望点击li显示出li的文本内容,如果给每个li绑定就得这么写:

<ul id="ul">
    <li onclick="handleClick(event)">1</li>
    <li onclick="handleClick(event)">2</li>
    <li onclick="handleClick(event)">3</li>
    <li onclick="handleClick(event)">4</li>
    <li onclick="handleClick(event)">5</li>
</ul>
const handleClick=(e)=>{
    console.log(e.target.innerHTML);
};

但如果通过事件代码,我们将点击行为委托给li共同的父元素ul,代码将更为清晰简单:

<ul id="ul">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
</ul>
const span = document.getElementById("span");
const handleClick = (e) => {
    span.innerHTML =`此时点击的是第${e.target.innerHTML}个li`;
};
const ul = document.querySelector("#ul");
ul.addEventListener("click", handleClick)

虽然事件被代理给了ul,但通过event.target我们还是能拿到实际操作的li。这让我想起了17我还在写JQ的年代,当li是动态遍历生成时,如果给li绑事件你会发现此时li其实是不存在的,这就导致事件绑定最终失败,而事件代理在性能更优的前景下更是巧妙解决了这一问题。

OK,关于原生事件监听与事件代理我们就介绍到这里,这部分知识也利于我们理解react的合成事件。

如果您发现该资源为电子书等存在侵权的资源或对该资源描述不正确等,可点击“私信”按钮向作者进行反馈;如作者无回复可进行平台仲裁,我们会在第一时间进行处理!

评价 0 条
风晓L1
粉丝 1 资源 2038 + 关注 私信
最近热门资源
银河麒麟桌面操作系统备份用户数据  121
统信桌面专业版【全盘安装UOS系统】介绍  114
银河麒麟桌面操作系统安装佳能打印机驱动方法  108
银河麒麟桌面操作系统 V10-SP1用户密码修改  100
最近下载排行榜
银河麒麟桌面操作系统备份用户数据 0
统信桌面专业版【全盘安装UOS系统】介绍 0
银河麒麟桌面操作系统安装佳能打印机驱动方法 0
银河麒麟桌面操作系统 V10-SP1用户密码修改 0
作者收入月榜
1

prtyaa 收益393.62元

2

zlj141319 收益217.55元

3

1843880570 收益214.2元

4

IT-feng 收益208.98元

5

风晓 收益208.24元

6

777 收益172.71元

7

Fhawking 收益106.6元

8

信创来了 收益105.84元

9

克里斯蒂亚诺诺 收益91.08元

10

技术-小陈 收益79.5元

请使用微信扫码

加入交流群

请使用微信扫一扫!