React合成事件的原理是什么

发布时间:2022-07-07 09:54:32 作者:iii
来源:亿速云 阅读:186

这篇文章主要讲解了“React合成事件的原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“React合成事件的原理是什么”吧!

事件介绍

什么是事件?

事件是在编程时系统内发生的动作或者发生的事情,而开发者可以某种方式对事件做出回应,而这里有几个先决条件

举个栗子

在机场等待检票,听到广播后排队检票

代码实现

// 检票事件
var event = new Event('check-ticket');
// 事件注册,并编写回调
elem.addEventListener('check-ticket', function (e) { 
  // 开始排队
  LiningUp()
});
// 事件触发,广播开始检票
elem.dispatchEvent(event);

React合成事件基础知识

什么是合成事件?

不是浏览器本身触发的事件,自己创建和触发的事件。

在React中事件的写法和原生事件写法的区别?

// HTML中的写法
<button onclick="handleClick()">
  Activate Lasers
</button>
// React中的写法
<button onClick={handleClick}>
  Activate Lasers
</button>

为什么会有合成事件?

合成事件机制简述

提供了一种“顶层注册,事件收集,统一触发”的事件机制

React合成事件实现原理

事件注册

时机:在fiber节点进入render阶段的complete阶段时,名为onClick的props会被识别为事件进行处理

function setInitialDOMProperties(
  tag: string,
  domElement: Element,
  rootContainerElement: Element | Document,
  nextProps: Object,
  isCustomComponentTag: boolean,
): void {
  for (const propKey in nextProps) {
    if (!nextProps.hasOwnProperty(propKey)) {
      ...
    } else if (registrationNameDependencies.hasOwnProperty(propKey)) {
        // 如果propKey属于事件类型,则进行事件绑定
        ensureListeningTo(rootContainerElement, propKey, domElement);
      }
    }
  }
}
// registrationNameDependencies为合成事件名和真实事件的映射,格式如下:
{
  onChange: ['change', 'click', 'focusin', 'focusout', 'input', 'keydown', 'keyup', 'selectionchange']
  onChangeCapture: ['change', 'click', 'focusin', 'focusout', 'input', 'keydown', 'keyup', 'selectionchange']
  onClick: ['click']
}

调用ensureListeningTo进行事件绑定

然后调用DOMPluginEventSystem.js中的addTrappedEventListener进行事件注册,而监听器listener是React通过createEventListenerWrapperWithPriority创建出优先级不同的时间监听包装器

总的来说,会有三种事件监听包装器:

事件触发-事件监听器做了什么

负责以不同的优先级权重来触发真正的事件流程

createEventListenerWrapperWithPriority中,根据eventPriority事件优先级不同调用事件dispatchDiscreteEventdispatchUserBlockingUpdatedispatchUserBlockingUpdatedispatchEvent进行事件绑定

export function createEventListenerWrapperWithPriority(
  targetContainer: EventTarget,
  domEventName: DOMEventName,
  eventSystemFlags: EventSystemFlags,
): Function {
  const eventPriority = getEventPriorityForPluginSystem(domEventName);
  let listenerWrapper;
  switch (eventPriority) {
    case DiscreteEvent:
      listenerWrapper = dispatchDiscreteEvent;
      break;
    case UserBlockingEvent:
      listenerWrapper = dispatchUserBlockingUpdate;
      break;
    case ContinuousEvent:
    default:
      listenerWrapper = dispatchEvent;
      break;
  }
  return listenerWrapper.bind(
    null,
    domEventName,
    eventSystemFlags,
    targetContainer,
  );
}

在每一个事件绑定函数中,会调用dispatchEventsForPlugins函数

function dispatchEventsForPlugins(
  domEventName: DOMEventName,
  eventSystemFlags: EventSystemFlags,
  nativeEvent: AnyNativeEvent,
  targetInst: null | Fiber,
  targetContainer: EventTarget,
): void {
  const nativeEventTarget = getEventTarget(nativeEvent);
  const dispatchQueue: DispatchQueue = [];
  // 通过不同事件类型插件进行事件对象合成,将合成事件放入事件队列中:dispatchQueue中
  extractEvents(
    dispatchQueue,
    domEventName,
    targetInst,
    nativeEvent,
    nativeEventTarget,
    eventSystemFlags,
    targetContainer,
  );
  // 执行dispatchQueue中具体事件执行路径下的事件
  processDispatchQueue(dispatchQueue, eventSystemFlags);
}
// 通过extractEvents合成的dispatchQueue的格式如下
[
  {
    // event是合成事件对象
    event, 
    // 具体的事件执行路径,currentTarget、listener等信息
    listeners: [
      {
        currentTarget: div.counter,
        instance: FiberNode {tag: 5, key: null, elementType: 'div', type: 'div', stateNode: div.counter, …},
        listener: e => {…}
      },
      {
        currentTarget: div.counter-parent,
        instance: FiberNode {tag: 5, key: null, elementType: 'div', type: 'div', stateNode: div.counter, …},
        listener: e => {…}
      }
    ] 
  }
]

React中模拟冒泡和捕获

原理:收集的事件放在dispatchQueue数组中,而冒泡和捕获的区别在于执行时机和顺序,那么我们只需要对数组按照不同顺序循环执行即可

function processDispatchQueueItemsInOrder(
  event: ReactSyntheticEvent,
  dispatchListeners: Array<DispatchListener>,
  inCapturePhase: boolean,
): void {
  let previousInstance;

  if (inCapturePhase) {
    // 事件捕获倒序循环
    for (let i = dispatchListeners.length - 1; i >= 0; i--) {
      const {instance, currentTarget, listener} = dispatchListeners[i];
      if (instance !== previousInstance && event.isPropagationStopped()) {
        return;
      }
      // 执行事件,传入event对象,和currentTarget
      executeDispatch(event, listener, currentTarget);
      previousInstance = instance;
    }
  } else {
    // 事件冒泡正序循环
    for (let i = 0; i < dispatchListeners.length; i++) {
      const {instance, currentTarget, listener} = dispatchListeners[i];
      // 如果事件对象阻止了冒泡,则return掉循环过程
      if (instance !== previousInstance && event.isPropagationStopped()) {
        return;
      }
      executeDispatch(event, listener, currentTarget);
      previousInstance = instance;
    }
  }
}

感谢各位的阅读,以上就是“React合成事件的原理是什么”的内容了,经过本文的学习后,相信大家对React合成事件的原理是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

推荐阅读:
  1. jquery 合成事件
  2. React事件处理机制的原理是什么

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

react

上一篇:python中内置函数ord()返回字符串的ASCII数值是什么

下一篇:C语言中二级指针与链表怎么应用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》