Skip to content
目录

事件的监听过程

setInitialDOMProperties

在初始化DOM节点的props阶段,会判断当前的prop key,是否是事件

typescript
if (registrationNameModules.hasOwnProperty(propKey)) {
  // registrationNameModules 就是在注入平台事件后,生产的对象
  // propKey 就是 registrationName 比如 onChange 、onClick 等
  if (nextProp != null) {
    // rootContainerElement 就是ReactDOM.render的第二个参数 也就是我们
    // 传入的id为root的DOM节点
    ensureListeningTo(rootContainerElement, propKey);
  }
}

ensureListeningTo

typescript
function ensureListeningTo(rootContainerElement, registrationName) {
  const isDocumentOrFragment =
    rootContainerElement.nodeType === DOCUMENT_NODE ||
    rootContainerElement.nodeType === DOCUMENT_FRAGMENT_NODE;
  // 获取当前的document
  const doc = isDocumentOrFragment
    ? rootContainerElement
    : rootContainerElement.ownerDocument;
  // 传入React事件名称以及 document
  // 这里的 registrationName 就是onChange等
  listenTo(registrationName, doc);
}

listenTo

typescript
export function listenTo(
  registrationName: string,
  mountAt: Document | Element,
) {
  // 拿到的是一个对象
  const isListening = getListeningForDocument(mountAt);
  // 获取当前事件的dependencies
  const dependencies = registrationNameDependencies[registrationName];
  for (let i = 0; i < dependencies.length; i++) {
    // dependency 就是click blur change 等等
    const dependency = dependencies[i];
    if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) {
      // 只有当isListening 没有,才会进入到这里
      // 也就是说 监听过 就不会重复监听了
      switch (dependency) {
        case TOP_SCROLL:
          trapCapturedEvent(TOP_SCROLL, mountAt);
          break;
        case TOP_FOCUS:
        case TOP_BLUR:
          trapCapturedEvent(TOP_FOCUS, mountAt);
          trapCapturedEvent(TOP_BLUR, mountAt);
          // We set the flag for a single dependency later in this function,
          // but this ensures we mark both as attached rather than just one.
          isListening[TOP_BLUR] = true;
          isListening[TOP_FOCUS] = true;
          break;
        case TOP_CANCEL:
        case TOP_CLOSE:
          if (isEventSupported(getRawEventName(dependency))) {
            trapCapturedEvent(dependency, mountAt);
          }
          break;
        case TOP_INVALID:
        case TOP_SUBMIT:
        case TOP_RESET:
          break;
        default:
          // 媒体相关的事件监听过了
          // 所以在这里除了不是媒体相关的事件,都需要监听
          const isMediaEvent = mediaEventTypes.indexOf(dependency) !== -1;
          if (!isMediaEvent) {
            // 冒泡阶段的监听
            trapBubbledEvent(dependency, mountAt);
          }
          break;
      }
      isListening[dependency] = true;
    }
  }
}

trapBubbledEvent

typescript
export function trapBubbledEvent(
  topLevelType: DOMTopLevelEventType,
  element: Document | Element,
) {
  if (!element) {
    return null;
  }
  // 判断当前事件是否是interactive类型,也就是需要跟用户交互的
  // 对于这类事件产生的任务,在计算任务的优先级的expirationTime会比较大(优先级较高)
  const dispatch = isInteractiveTopLevelEventType(topLevelType)
    ? dispatchInteractiveEvent
    : dispatchEvent;

  addEventBubbleListener(
    element,
    getRawEventName(topLevelType),
    dispatch.bind(null, topLevelType),
  );
}

isInteractiveTopLevelEventType

typescript
isInteractiveTopLevelEventType(topLevelType: TopLevelType): boolean {
    const config = topLevelEventsToDispatchConfig[topLevelType];
    return config !== undefined && config.isInteractive === true;
  },

topLevelEventsToDispatchConfig

topLevelEventsToDispatchConfig的生成

typescript
function addEventTypeNameToConfig(
  [topEvent, event]: EventTuple,
  isInteractive: boolean,
) {
  const capitalizedEvent = event[0].toUpperCase() + event.slice(1);
  const onEvent = 'on' + capitalizedEvent;

  const type = {
    phasedRegistrationNames: {
      bubbled: onEvent,
      captured: onEvent + 'Capture',
    },
    dependencies: [topEvent],
    isInteractive,
  };
  eventTypes[event] = type;
  topLevelEventsToDispatchConfig[topEvent] = type;
}

// 高优先级用户交互的事件
interactiveEventTypeNames.forEach(eventTuple => {
  addEventTypeNameToConfig(eventTuple, true);
});
// 低优先级用户不需要交互的事件
nonInteractiveEventTypeNames.forEach(eventTuple => {
  addEventTypeNameToConfig(eventTuple, false);
});

addEventBubbleListener

这就是最终事件监听的方法

typescript
export function addEventBubbleListener(
  element: Document | Element,
  eventType: string,
  listener: Function,
): void {
  element.addEventListener(eventType, listener, false);
}

备案号: 浙ICP备2023000081号