最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 写给进阶玩家的 React 事件系统原理

    正文概述 掘金(ELab)   2021-06-21   468

    【 简介 】

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

    react官方描述 写给进阶玩家的 React 事件系统原理 分别打印出合成事件对象e和原生对象e.nativeEvent 写给进阶玩家的 React 事件系统原理

    【 React 事件系统架构 】

    写给进阶玩家的 React 事件系统原理

    _【 核心代码 】// _我们可以将react系统分成注册和执行两部分去理解:

    一、注册:

    // 
    function enqueuePutListener(inst, registrationName, listener, transaction) {
        ...
      var isDocumentFragment = containerInfo._node && containerInfo._node.nodeType === DOC_FRAGMENT_TYPE;
      1. 找到document
      var doc = isDocumentFragment ? containerInfo._node : containerInfo._ownerDocument;
      2. 注册事件,将事件注册到document上
      3. listenTo(registrationName, doc);
      存储事件,放入事务队列中
    }
    

    react事件系统内部对事件在不同浏览器上的执行做了兼容因此无需使用者考虑浏览器相关情况:

      listen: function listen(target, eventType, callback) {
        if (target.addEventListener) {
          将原生事件添加到target这个dom上,也就是上边传递的document上
          这就是只有document这个DOM节点上有原生事件的原因
          target.addEventListener(eventType, callback, false);
          ...
        } else if (target.attachEvent) {
          target.attachEvent('on' + eventType, callback);
          ...
        }
      }
    

    二、执行:

    事件分发dispatchEvent(react合成事件的冒泡机制)

    function handleTopLevelImpl(bookKeeping) {
      1. 找到事件触发的DOM和React Component
      var nativeEventTarget = getEventTarget(bookKeeping.nativeEvent);
      var targetInst = ReactDOMComponentTree.getClosestInstanceFromNode(nativeEventTarget);
    
      2. 执行事件回调前,先由当前组件向上遍历它的所有父组件。
      得到ancestors这个数组,这个数组同时也是冒泡顺序。
      var ancestor = targetInst;
      do {
        bookKeeping.ancestors.push(ancestor);
        ancestor = ancestor && findParent(ancestor);
      } while (ancestor);
    
      这个顺序就是冒泡的顺序,并且我们发现不能通过stopPropagation来阻止'冒泡'。
      for (var i = 0; i < bookKeeping.ancestors.length; i++) {
        targetInst = bookKeeping.ancestors[i];
        ReactEventListener._handleTopLevel(bookKeeping.topLevelType, targetInst, bookKeeping.nativeEvent, getEventTarget(bookKeeping.nativeEvent));
      }
    }
    

    handleTopLevel 构造合成事件并执行(依赖EventPluginHub)

    1. 初始化时将eventPlugin注册到EventPluginHub中,不同plugin分别构造不同类型的合成事件
      ReactInjection.EventPluginHub.injectEventPluginsByName({
        ...不同插件
      });
      
    2. 将事件放入事件池:
       EventPluginHub.enqueueEvents(events);
    3. 再处理队列中的事件,包括之前未处理完的:
       EventPluginHub.processEventQueue(false);
    

    【 合成事件、原生事件混用demo】

    刚接触react的同学,往往在react事件使用时会与原生事件混合(这里并非指责这种混用行为,只是在混用阶段需要区分出react时间系统和js本身事件的执行差异),时常会有事件执行出现不符合预期的情况,这里我们用一个小demo来感受下二者执行的差异: 写给进阶玩家的 React 事件系统原理 写给进阶玩家的 React 事件系统原理 打印出执行结果:

    写给进阶玩家的 React 事件系统原理

    由此我们可以了解到如下原生事件、react事件、document上挂载事件执行顺序:

    写给进阶玩家的 React 事件系统原理

    【 合成事件存在意义 】

    1.统一管理(document)

    react事件集中在document上集中管理

    2.不同浏览器兼容问题

    3.减少事件创建销毁的性能损耗(避免频繁的垃圾回收机制)

    react事件队列的存储和取出使用缓解了dom元素注册销毁所消耗的性能

    4.利用合成事件的冒泡从document中触发的特性

    【 合成事件中存在的问题 】

    1.原生事件和合成事件混用时原生事件对入react合成事件的影响

    • 原生事件中禁止冒泡会阻止react合成事件的执行
    • react合成事件禁止冒泡不会对原生生效

    2.事件池中中事件处理函数全部被调用之后,所有属性都会被置为 null

    写给进阶玩家的 React 事件系统原理 写给进阶玩家的 React 事件系统原理

    避免方法:
    • e.persist() //可以阻止事件池清掉取出事件
    • 17版本react会有废弃事件池等更改,此现象也不会存在

    3.不同版本的 React 组件嵌套使用时,e.stopPropagation无法正常工作(两个不同版本的事件系统是独立的,都注册到document时的时间不相同)

    【 相关参考 】

    • react.docschina.org/
    • github.com/facebook/re…
    • React 17 要来了,非常特别的一版 - 梦烬 - 博客园

    起源地下载网 » 写给进阶玩家的 React 事件系统原理

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元