Skip to content
目录

事件对象的产生,跟事件的类型有关,分别各自定义的,这里简单的阅读一下ChangeEventPlugin的extractEvents

ChangeEventPlugin 的 extractEvents

typescript
extractEvents: function(
    topLevelType,
    targetInst,
    nativeEvent,
    nativeEventTarget,
  ) {
    const targetNode = targetInst ? getNodeFromInstance(targetInst) : window;

    let getTargetInstFunc, handleEventFunc;
    if (shouldUseChangeEvent(targetNode)) {
      getTargetInstFunc = getTargetInstForChangeEvent;
    } else if (isTextInputElement(targetNode)) {
      if (isInputEventSupported) {
        getTargetInstFunc = getTargetInstForInputOrChangeEvent;
      } else {
        getTargetInstFunc = getTargetInstForInputEventPolyfill;
        handleEventFunc = handleEventsForInputEventPolyfill;
      }
    } else if (shouldUseClickEvent(targetNode)) {
      getTargetInstFunc = getTargetInstForClickEvent;
    }
    // 根据特定的节点类型,生成一个获取当前事件对象目标Fiber实例的方法
    if (getTargetInstFunc) {
      const inst = getTargetInstFunc(topLevelType, targetInst);
      if (inst) {
        // 支持创建事件对象的真正方法
        const event = createAndAccumulateChangeEvent(
          inst,
          nativeEvent,
          nativeEventTarget,
        );
        return event;
      }
    }

    if (handleEventFunc) {
      handleEventFunc(topLevelType, targetNode, targetInst);
    }

    // When blurring, set the value attribute for number inputs
    if (topLevelType === TOP_BLUR) {
      handleControlledInputBlur(targetNode);
    }
  },
};

createAndAccumulateChangeEvent

typescript
function createAndAccumulateChangeEvent(inst, nativeEvent, target) {
  // 从合成事件对象池获取event对象
  // 这里对象池也是为了避免频繁的对象创建,造成不必要的内存开销
  const event = SyntheticEvent.getPooled(
    eventTypes.change,
    inst,
    nativeEvent,
    target,
  );
  event.type = 'change';
  // Flag this event loop as needing state restore.
  // 这个方法暂时没发现具体的作用
  enqueueStateRestore(target);
  // 处理两个阶段  ‘捕获’ ‘冒泡阶段’ 
  // 以及事件真正要调用的函数会被挂在到event对象上
  accumulateTwoPhaseDispatches(event);
  return event;
}

accumulateTwoPhaseDispatches

typescript
export function accumulateTwoPhaseDispatches(events) {
  forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
}
typescript
function accumulateTwoPhaseDispatchesSingle(event) {
  if (event && event.dispatchConfig.phasedRegistrationNames) {
    traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event);
  }
}

traverseTwoPhase

typescript
export function traverseTwoPhase(inst, fn, arg) {
  const path = [];
  while (inst) {
    path.push(inst);
    inst = getParent(inst);
  }
  let i;
  // 从父到子执行事件的捕获操作
  for (i = path.length; i-- > 0; ) {
    fn(path[i], 'captured', arg);
  }
  // 从子到付执行事件的冒泡操作
  for (i = 0; i < path.length; i++) {
    fn(path[i], 'bubbled', arg);
  }
}

accumulateDirectionalDispatches

typescript
function accumulateDirectionalDispatches(inst, phase, event) {
  // 获取事件绑定的函数
  const listener = listenerAtPhase(inst, event, phase);
  if (listener) {
    // 将当前listener存到Fiber节点的 _dispatchListeners 对象上
    event._dispatchListeners = accumulateInto(
      event._dispatchListeners,
      listener,
    );
    event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
  }
}

获取事件绑定的listener过程

typescript
function listenerAtPhase(inst, event, propagationPhase: PropagationPhases) {
  const registrationName =
    event.dispatchConfig.phasedRegistrationNames[propagationPhase];
  return getListener(inst, registrationName);
}
typescript
export function getListener(inst: Fiber, registrationName: string) {
  let listener;
  const stateNode = inst.stateNode;
  if (!stateNode) {
    return null;
  }
  // 从DOM节点获取props
  // 因为props被设置到了dom节点的熟悉上面了
  const props = getFiberCurrentPropsFromNode(stateNode);
  if (!props) {
    return null;
  }
  // 直接获取listener 也就是事件绑定的那个函数
  listener = props[registrationName];
  if (shouldPreventMouseEvent(registrationName, inst.type, props)) {
    return null;
  }
  return listener;
}

备案号: 浙ICP备2023000081号