• React事件机制


    React事件机制是什么

          React基于浏览器的事件机制自身实现了一套事件机制,包括事件注册、事件的合成、事件冒泡、事件派发等。

    合成事件

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

    原生事件对象

    在这里插入图片描述
    在这里插入图片描述
          由此可见,React中的eventsyntheticEvent,模拟出来了Dom事件所有的能力。而event.nativeEvent才是原生事件对象。
    在这里插入图片描述
    在这里插入图片描述

          由此可见,event.nativeEvent.target是当前触发元素,而event.nativeEvent.currentTarget是绑定事件的元素。

    事件注册机制

          React事件注册过程其实主要做了2件事:事件注册、事件存储。

    • 事件注册 : 组件挂载阶段,根据组件内的声明的事件类型onclickonchange 等,给 document 上添加事件 addEventListener,并指定统一的事件处理程序 dispatchEvent

    • 事件存储 :就是把 react 组件内的所有事件统一的存放到一个对象里,缓存起来,为了在触发事件的时候可以查找到对应的方法去执行。

    事件注册

    enqueuePutListener(this, propKey, nextProp, transaction);
    
    • 1

          在这个方法里会进行事件的注册以及事件的存储,包括冒泡和捕获的处理。
          根据当前的组件实例获取到最高父级——也就是document,然后执行方法 listenTo -——也是最关键的一个方法,进行事件绑定处理。最后执行 EventListener.listen(冒泡)或者 EventListener.capture(捕获),单看下冒泡的注册,其实就是 addEventListener的第三个参数是 false。到这里事件注册就完事儿了。

    事件存储

          开始事件的存储,在 react 里所有事件的触发都是通过 dispatchEvent方法统一进行派发的,而不是在注册的时候直接注册声明的回调,来看下如何存储的 。

          react 把所有的事件和事件类型以及react 组件进行关联,把这个关系保存在了一个 map里,也就是一个对象里(键值对),然后在事件触发的时候去根据当前的 组件id和 事件类型查找到对应的 事件fn

          这里的组件 id 就是组件的唯一标识,然后和fn进行关联,在触发阶段就可以找到相关的事件回调。

    执行顺序

    import  React  from 'react';
    class App extends React.Component{
     
      constructor(props) {
        super(props);
        this.parentRef = React.createRef();
        this.childRef = React.createRef();
      }
      componentDidMount() {
        console.log("React componentDidMount!");
        this.parentRef.current?.addEventListener("click", () => {
          console.log("原生事件:父元素 DOM 事件监听!");
        });
        this.childRef.current?.addEventListener("click", () => {
          console.log("原生事件:子元素 DOM 事件监听!");
        });
        document.addEventListener("click", (e) => {
          console.log("原生事件:document DOM 事件监听!");
        });
      }
      parentClickFun = () => {
        console.log("React 事件:父元素事件监听!");
      };
      childClickFun = () => {
        console.log("React 事件:子元素事件监听!");
      };
      render() {
        return (
          <div ref={this.parentRef} onClick={this.parentClickFun}>
            <div ref={this.childRef} onClick={this.childClickFun}>
              分析事件执行顺序
            </div>
          </div>
        );
      }
    }
    export default App;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    输出顺序为:

    原生事件:子元素 DOM 事件监听! 
    原生事件:父元素 DOM 事件监听! 
    React 事件:子元素事件监听! 
    React 事件:父元素事件监听! 
    原生事件:document DOM 事件监听! 
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以得到以下结论:

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

    所以想要阻止不同时间段的冒泡行为,对应使用不同的方法,对应如下:

    1. 阻止合成事件之间的冒泡:用stopPropagation( );
    2. 阻止合成事件与最外层 document 上的事件间的冒泡 : 用e.nativeEvent.stopImmediatePropagation();
  • 相关阅读:
    回归预测 | MATLAB实现MLP多层感知机模型多输入多输出回归预测
    vue实现水平switch多个切换按钮
    C#使用OpenCv(OpenCVSharp)图像轮廓凸包检测与绘制
    计算机毕设之基于Python+django+MySQL可视化的学习系统的设计与实现
    Windows应急响应信息采集工具
    测试平台项目部署一(手动部署)
    【JAVA】excel读取常见问题(涉及格式:xls、xlsx)
    SpringCloud_第1章_入门到精通()
    面试资料快速复习 Git常用命令(简单实用)
    习题练习 C语言(暑期第四弹)
  • 原文地址:https://blog.csdn.net/Darlingmi/article/details/123716811