React 合成事件

2023-11-05

文章借鉴 pingan8787 React合成事件 和 React合成事件官方文档

React 合成事件

一、概念介绍

React合成事件是React 模拟原生DOM事件所有能力 的一个事件对象。
根据 W3C规范 来定义合成事件,兼容所有浏览器,拥有与浏览器原声事件相同的接口。

合成事件除了拥有和浏览器原生事件相同的接口,包括stopPropagation()preventDefault()

⚠️ 在React中,所有事件都是合成的,不是原生DOM事件,可以通过 e.nativeEvent 属性获取原生DOM事件。合成事件不会映射到原生事件;例如:在onMouseLeave事件中event.nativeEvent 将指向mouseout 事件;

const handleClick = (e) => console.log(e.nativeEvent);;
const button = <button onClick={handleClick}>Leo 按钮</button>

二、为什么出现这个技术?

  • 浏览器兼容,实现更好的跨平台
    顶层事件代理机制:保证冒泡一致性,可以跨浏览器执行。将不同平台事件模拟成合成事件;

  • 避免垃圾回收
    React引入事件池,在事件池中获取或释放事件对象;
    React事件对象不会被释放掉,而是存入一个数组中;当事件触发,就从这个数组中弹出,避免频繁地创建和销毁(垃圾回收);

  • 方便事件统一管理和事务机制

三、原生事件回顾

  • 事件捕获:当某个元素触发某个事件(比如:onClick),顶层对象(document)就会发出一个事件流,随着DOM树的节点向目标节点流去,直到到达真正发生的目标元素;
  • 事件目标:执行处理函数
  • 事件冒泡:从目标元素开始,往顶层元素传播;途中有节点绑定了相应的事件处理函数,这些函数就会被触发一次。⚠️ 想要阻止事件冒泡,可以使用e.stopPropagation() 或者e.cancleBubble=true (IE)来阻止事件等等冒泡传播。
  • 事件委托 / 事件代理
    将一个响应事件委托到另一个元素;子节点被点击,click事件向上冒泡,父节点捕获到事件后,进行处理;(可以减少内存消耗和动态绑定事件

四、合成事件和原生事件的区别

  • 命名方式不同
    原生:onclick(纯小写)
    React:onClick(小驼峰)
  • 事件处理函数写法不同
    原生事件处理函数为字符串,React JSX语法中,传入一个函数作为事件处理函数
// 原生事件 事件处理函数写法
<button onclick="handleClick()">Leo 按钮命名</button>
// React 合成事件 事件处理函数写法
const button = <button onClick={handleClick}>Leo 按钮命名</button>
  • 阻止默认行为方式的不同
    原生事件:通过返回false 方式阻止默认行为;
    React:显式使用preventDefault() 方法阻止;比如阻止<a>标签默认打开新页面为例;
// 原生事件阻止默认行为方式
<a href="https://www.pingan8787.com" 
  onclick="console.log('Leo 阻止原生事件~'); return false"
>
  Leo 阻止原生事件
</a>

// React 事件阻止默认行为方式
const handleClick = e => {
  e.preventDefault();
  console.log('Leo 阻止原生事件~');
}
const clickElement = <a href="https://www.pingan8787.com" onClick={handleClick}>
  Leo 阻止原生事件
</a>
  • 事件处理器返回false时,不阻止事件传递;可以考虑调用e.stopPropagation()e.preventDefault()
  • 支持的事件:
    如果需要注册捕获阶段的事件处理函数,应该为事件名添加Capture ;例如:处理捕获阶段的点击事件请使用 onClickCapture 而不是 onClick

五、React事件和原生事件的执行顺序

合成事件的执行顺序
在React中,“合成事件” 会以事件委托的方式绑定到组件最上层,并在组件卸载阶段自动销毁绑定的事件。

  • React 所有事件都挂载在 document 对象上;
  • 当真实 DOM 元素触发事件,会冒泡到 document 对象后,再处理 React 事件;
  • 所以会先执行原生事件,然后处理 React 事件;
  • 最后真正执行 document 上挂载的事件。

原生事件 —— > React事件 —— > document事件

在页面上点击按钮,事件开始在原生DOM上走捕获冒泡流程,React监听的是document上的冒泡阶段;事件冒泡到document后,React将事件再派发到组件树中,然后事件开始在组件树DOM中走捕获冒泡流程。(React上监听的是document上的事件)

同一元素如果对同一类型的事件绑定来多个处理器,会按绑定的顺序来执行;

React中阻止事件冒泡的问题:

  • 事件处理器:
    默认情况下,事件处理器在事件的冒泡阶段执行,默认下:document.addEventListener() 中的 useCapture 参数为 false;
<button onclick="btnClickHandler(event)">CLICK ME</button>
<script>
  document.addEventListener("click", function(event) {
    console.log("document clicked");
  }); // 
  function btnClickHandler(event) {
    console.log("btn clicked");
  }
</script>

以上全部都是原生代码,所以输出:(最后冒泡到document

btn clicked
document clicked
  • 阻止事件的冒泡
    调用事件身上的stopPropagation() 可阻止事件往上冒泡,可以实现想要的元素处理该事件,而其他元素接收不到。(原生事件如果执行了stopPropagation,所有元素的事件将无法冒泡到document,这样的话,所有的React事件都将无法被注册。)

同一元素上同一类型的事件(比如:click事件)绑定来多个事件处理器,本来处理器按绑定的先后顺序来执行,但是如果其中一个调用了stopImmediatePropagation,不但会阻止事件冒泡,还会组织这个元素后续其他事件处理器的执行。

<button onclick="btnClickHandler(event)">CLICK ME</button>
<script>
  document.addEventListener(
    "click",
    function(event) {
      console.log("document clicked");
    },
    false
  );

  function btnClickHandler(event) {
    event.stopPropagation();
    console.log("btn clicked");
  }
</script>

输出:

btn clicked
  • e.stopPropagation

e.stopPropagation() 只能阻止合成事件间冒泡,即下层的合成事件,不会冒泡到上层的合成事件。事件本身还都是在 document 上执行。所以最多只能阻止 document 事件不能再冒泡到 window 上。
(document事件不执行:原生——React事件(e.stopPropagation())——document事件)

  • e.nativeEvent.stopImmediatePropagation

在React中,一个组件只能绑定一个同类型的事件监听器,当重复定义时,后面的监听器会覆盖之前的;
事实上 nativeEventstopImmediatePropagation只能阻止绑定在 document 上的事件监听器。而合成事件上的e.nativeEvent.stopImmediatePropagation()能阻止合成事件不会冒泡到 document 上。

六、合成事件的事件池

事件池

1、事件池介绍

合成事件对象池,是 React 事件系统提供的一种性能优化方式。合成事件对象在事件池统一管理,不同类型的合成事件具有不同的事件池
事件池未满:React创建新的事件对象,派发给组件;
事件池装满:React从事件池中复用事件对象,派发给组件;
合成事件对象的事件处理函数全部被调用之后,所有属性都会被置为 null

2、React 17版本不使用事件池

e.persist() 将不再生效;因为合成事件不再放入事件池中;

七、常见问题

1、React 事件this指向

JSX回调函数中的this经常会出问题,在class方法不会默认绑定this;

解决办法:

  • 使用 bind 方法绑定 this
    this.clickFun = this.clickFun.bind(this);
class App extends React.Component<any, any> {
  constructor(props: any) {
    super(props);
    this.clickFun = this.clickFun.bind(this);
  }
  clickFun() {
    console.log("React this 指向问题");
  }
  render() {
    return (
        <div onClick={this.clickFun}>React this 指向问题</div>
    );
  }
}
export default App;
  • 将使用this的方法写为使用箭头函数定义
    clickFun = () => {}
class App extends React.Component<any, any> {
  clickFun = () => {
    console.log("React this 指向问题");
  }
  render() {
    return (
        <div onClick={this.clickFun}>React this 指向问题</div>
    );
  }
}
export default App;
  • 在回调函数中使用箭头函数
class App extends React.Component<any, any> {
  // 省略其他代码
  clickFun() {
    console.log("React this 指向问题"); 
  }
  render() {
    return (
        <div onClick={() => this.clickFun()}>React this 指向问题</div>
    );
  }
}
export default App;

2、向事件传递参数问题

const List = [1,2,3,4];
class App extends React.Component<any, any> {
  // 省略其他代码
  clickFun (id) {console.log('当前点击:', id)}
  render() {
    return (
	   <div>
	     <h1>第一种:通过 bind 绑定 this 传参</h1>
	       {
		      	List.map(item => 
		      		<div onClick={this.clickFun.bind(this, item)}>
		      			按钮:{item}
		      		</div>
		      	)
	       }
	     <h1>第二种:通过箭头函数绑定 this 传参</h1>
	    	{
	      		List.map(item =>
			      	<div onClick={() => this.clickFun(item)}>
			      	 	按钮:{item}
			      	</div>
			    )
	        }
	    </div>
    );
  }
}
export default App;

八、支持的事件

  • onFocus
    onFocus 事件在元素聚焦时被调用;比如:用户点击文本输入框,就会调用该事件;
  • onBlur
    onBlur事件在失去焦点时被调用;比如:当用户在已聚焦的文本输入框外点击时,就会被调用;
  • 监听焦点的进入与离开
    React官方文档:合成事件
    可以使用currentTargetrelatedTarget来区分聚焦和失去焦点是否来自父元素外部;下面的例子展示来如何监听一个子元素的聚焦、元素本身的聚焦、以及整个子树进入焦点或离开焦点。
<div
  tabIndex={1}
  onFocus={(e) => {
  	// currentTarget 指的是当前节点
    if (e.currentTarget === e.target) {
      console.log('focused self');
    } else {
      console.log('focused child', e.target);
    }
    if (!e.currentTarget.contains(e.relatedTarget)) {
      // Not triggered when swapping focus between children
      console.log('focus entered self');
    }
  }}
>
	<input id="1" />
	<input id="2" />
</div>
  • 表单事件
onChange、onInput、onReset、onSubmit、onInvalid
  • 通用事件
onError		onLoad
  • 鼠标事件
    onMouseEnteronMouseLeave这两个事件从离开的元素向进入的元素传播,不是正常的冒泡,也没有捕获阶段;
onMOuseMove		onMouseOut		onMouseOver		onMouseUp
onMouseEnter	onMouseLeave 
  • 指针事件:不是每个浏览器都支持指针事件、支持的浏览器有:Chrome、Firefox、Edge、Internet Explorer;
    onPointerEnteronPointerLeave 事件从离开的元素向进入的元素传播,不是正常的冒泡,也没有捕获阶段。
  • 选择事件
  • 触摸事件
  • UI事件(onScroll,从React17开始,onScroll事件在React中不再冒泡)
  • 滚轮事件(onWheel)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React 合成事件 的相关文章

  • 怎么建立一个自己的博客

    怎么建立一个自己的博客 1 写在开头 其实我自己写的文章也不多 只是看到有些东西会做一下记录 所以部署一个自己的博客来记录这些东西也就会方便很多 而Hexo框架的博客使用方便对电脑要求也不高 并且有很多可以使用的主题 所以就用它把 先来看看

随机推荐

  • 古典密码算法(移位密码算法、维吉尼亚算法)

    古典密码算法 凯撒 维吉尼亚 A 1 1 移位密码算法 实验目的 1 学习移位密码的原理 2 学习移密码的实现 实验原理 算法原理 a 移位密码就是对26个字母进行移位操作 可以移动任意位数 这样就实现了对明文的加密 移位操作简单易行 因此
  • MySQL参数之max_connections

    连接请求的变量 max connections MySQL的最大连接数 增加该值增加mysqld 要求的文件描述符的数量 如果服务器的并发连接请求量比较大 建议调高此值 以增加并行连接数量 当然这建立在机器能支撑的情况下 因为如果连接数越多
  • QTday1(第一个QT界面、常用类与组件)

    一 Xmind整理 Assistant帮助文档的使用 设计师界面的介绍 各文件之间调用方式 二 上课笔记整理 1 第一个QT界面 创建自定义类时需要指定父类 第一个界面的相关操作 include mainwindow h include
  • kafka常用运维命令

    列出所有topic bin kafka topics sh zookeeper localhost 2181 list 说明 其实就是去检查zk上节点的 brokers topics子节点 打印出来 创建topic bin kafka to
  • MatLab 隨機生成矩阵 复矩阵 单位下三角实矩阵 单位下三角复矩阵 矩阵求逆 矩阵乘法 matlab代码

    1 驗證 單位對角實矩陣的逆矩陣計算結果 2 驗證 單位對焦複矩陣的逆矩陣計算結果 n 7 real number field A rand n n L eye n for j 1 n L j 1 n j A j 1 n j end L L
  • ue4的UPROPERTY()

    继续学习B站的up主来自程序员的暴击的视频教程 我的理解就是属性 这个成员变量如何用 初步判断 只读和可读写 在myShowActor类里两个成员变量 UPROPERTY VisibleAnywhere Category Start int
  • 上海区块链会议演讲ppt_演讲和会议的软件开发人员指南

    上海区块链会议演讲ppt 软件开发会议提供了许多机会来促进您作为软件开发人员的职业发展 正如我们在网络一章中讨论的那样 参加会议可能是一个很好的网络机会 但是它们也是向该领域一些最高级程序员学习的好地方 但是 如果您真的想从软件开发会议中获
  • learn more study less:如何高效学习

    博主狂言 几句有用的话 两个序 前言 如何使用本书 整体性学习策略 learn more study less 什么是整体性学习 结构 模型 熟悉的结构成熟结构 高速公路 整体性学习的顺序 获取阶段 理解阶段 拓展阶段 纠错阶段 应用阶段
  • 适用于嵌入式单片机的差分升级通用库+详细教程

    文章目录 1 什么是差分 增量升级 2 差分升级实现原理 3 关键点一 差分包制作过程 4 关键点二 嵌入式设备中差分算法库的移植 还原差分包 4 1 移植开关算法库代码 4 2 使用该库的流程 4 2 1 使用库的接口 4 2 2 接口使
  • cvui.h 使用总结

    很多情况下个人更多用QT搭配opencv进行一系列开发 QT可以迅速开发出合乎要求的界面 但是实际上 试验过程中并不需要一个美观且功能齐全的界面 使用opencv进行图像处理 可能反反复复使用的是按键 勾选按钮 图片显示 参数修改或者显示等
  • rk3588 与 rk3399 差异比较

    rk3588 与 rk3399 差异比较 在2016年中 瑞芯微 Rockchip 在深圳会展中心召开首届VR生态链对接峰会 正式发布 VR 旗舰级产品 RK3399 在2021年底 瑞芯微 Rockchip 在福州第六届开发者大会 正式发
  • gradle wapper时异常(task with that name already exists)

    场景 新服务发布到测试环境打包失败 原因 1 种子项目配置了gradle版本 导入本地的时候选择使用项目的gradle Use default gradle wrapper recommended 2 直接在terminal里面输入 gra
  • IntelliJ IDEA 2017.3.1 使用手册

    因为CSDN博客时不时会报错 后续更新在 https my oschina net datadev blog 2876471 目录 1 激活 首次设置 2 创建maven项目 3 执行maven命令 4 创建maven moudle工程 5
  • mmyolo训练yolov5~ppyoloe

    使用mmyolo检测工具箱 完成yolo系列算法的训练 包括环境的搭建及yolo系列算法的配置文件等 mmyolo官方地址 https github com open mmlab mmdeploy 相关文档 https github com
  • 干货满满【JVM监控及诊断工具-GUI篇】

    JVM监控及诊断工具 GUI篇 3 1 工具概述 使用上一章命令行工具或组合能帮您获取目标Java应用性能相关的基础信息 但它们存在下列局限 1 无法获取方法级别的分析数据 如方法间的调用关系 各方法的调用次数和调用时间等 这对定位应用性能
  • Recylerview(list,九宫格,瀑布流布局)

    package com example recyclerview import android support v7 app AppCompatActivity import android os Bundle import android
  • Java中类和对象的关系

    一 基本概念 1 类 类是一个模板 它描述一类对象的行为和状态 比如一张汽车设计图纸 2 对象 对象表示现实世界中一个具体的事物 对象是类的一个实例 有状态和行为 例如 一条狗是一个对象 它的状态有 颜色 名字 品种 行为有 摇尾巴 叫 吃
  • 闲来无事搭个代理池子

    基于ProxyPool创建Proxifier代理 如题目所见 闲来无事在做测试时发现被某网站封了IP 为防止再被封掉 因此有了这篇文章和搭建过程 0x01 安装redis服务 ubuntu16 04 apt get install redi
  • FISCO BCOS(十五)——— Windows下的go环境配置及beego环境配置并解决bee run报错问题

    1 下载地址 https golang google cn dl 2 双击打开下载的文件 一路按照默认点击下一步 安装位置可选 默认安装在c盘 3 go环境配置 很重要的 在系统变量名中新建变量名 GOPATH 变量值 E go space
  • React 合成事件

    文章借鉴 pingan8787 React合成事件 和 React合成事件官方文档 React 合成事件 一 概念介绍 React合成事件是React 模拟原生DOM事件所有能力 的一个事件对象 根据 W3C规范 来定义合成事件 兼容所有浏