React合成事件是React提供的一种事件处理机制,它抽象了浏览器原生事件,提供了一些额外的特性和优化。
React合成事件的主要特点包括:
React合成事件的具体实现方式包括:
stopPropagation()
、preventDefault()
等)。事件监听使用addEventListener
来实现冒泡和捕捉
import { registerTwoPhaseEvent } from "./EventRegistry";
export function createRoot(
container: Element | Document | DocumentFragment,
options?: CreateRootOptions
): RootType {
const rootContainerElement: Document | Element | DocumentFragment =
container.nodeType === COMMENT_NODE
? (container.parentNode: any)
: container;
// 在createRoot的时候监听事件,listenToAllSupportedEvents中调用EventListener.js中的监听方法来监听事件,如addEventBubbleListener,addEventBubbleListener
listenToAllSupportedEvents(rootContainerElement);
// $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions
return new ReactDOMRoot(root);
}
// const allNativeEvents: Set<DOMEventName> = new Set();
export function listenToAllSupportedEvents(rootContainerElement: EventTarget) {
if (!(rootContainerElement: any)[listeningMarker]) {
(rootContainerElement: any)[listeningMarker] = true;
allNativeEvents.forEach(domEventName => {
// We handle selectionchange separately because it
// doesn't bubble and needs to be on the document.
if (domEventName !== 'selectionchange') {
if (!nonDelegatedEvents.has(domEventName)) {
//注册冒泡阶段
listenToNativeEvent(domEventName, false, rootContainerElement);
}
//注册捕获阶段
listenToNativeEvent(domEventName, true, rootContainerElement);
}
});
}
}
export function listenToNativeEvent(
domEventName: DOMEventName,
isCapturePhaseListener: boolean,
target: EventTarget,
): void {
let eventSystemFlags = 0;
if (isCapturePhaseListener) {
eventSystemFlags |= IS_CAPTURE_PHASE;
}
//注册监听函数
addTrappedEventListener(
target,
domEventName,
eventSystemFlags,
isCapturePhaseListener,
);
}
function addTrappedEventListener(
targetContainer: EventTarget,
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
isCapturePhaseListener: boolean,
isDeferredListenerForLegacyFBSupport?: boolean,
) {
let listener = createEventListenerWrapperWithPriority(
targetContainer,
domEventName,
eventSystemFlags,
);
// 后面的方法中调用addEventCaptureListener,addEventBubbleListenerWithPassiveFlag,addEventBubbleListener等函数
unsubscribeListener = addEventCaptureListener(
targetContainer,
domEventName,
listener,
);
}
// EventListener.js
export function addEventBubbleListener(
target: EventTarget,
eventType: string,
listener: Function
): Function {
target.addEventListener(eventType, listener, false);
return listener;
}
export function addEventCaptureListener(
target: EventTarget,
eventType: string,
listener: Function
): Function {
target.addEventListener(eventType, listener, true);
return listener;
}
const topLevelEventsToReactNames: Map<DOMEventName, string | null> = new Map();
// DOMEventProperties.js
function registerSimpleEvent(domEventName: DOMEventName, reactName: string) {
topLevelEventsToReactNames.set(domEventName, reactName);
registerTwoPhaseEvent(reactName, [domEventName]);
}
export function registerSimpleEvents() {
for (let i = 0; i < simpleEventPluginEvents.length; i++) {
const eventName = ((simpleEventPluginEvents[i]: any): string);
const domEventName = ((eventName.toLowerCase(): any): DOMEventName);
const capitalizedEvent = eventName[0].toUpperCase() + eventName.slice(1);
registerSimpleEvent(domEventName, "on" + capitalizedEvent);
}
// Special cases where event names don't match.
registerSimpleEvent(ANIMATION_END, "onAnimationEnd");
registerSimpleEvent(ANIMATION_ITERATION, "onAnimationIteration");
registerSimpleEvent(ANIMATION_START, "onAnimationStart");
registerSimpleEvent("dblclick", "onDoubleClick");
registerSimpleEvent("focusin", "onFocus");
registerSimpleEvent("focusout", "onBlur");
registerSimpleEvent(TRANSITION_END, "onTransitionEnd");
}
// EventRegistry.js
const allNativeEvents: Set<DOMEventName> = new Set();
export function registerTwoPhaseEvent(
registrationName: string,
dependencies: Array<DOMEventName>
): void {
registerDirectEvent(registrationName, dependencies);
registerDirectEvent(registrationName + "Capture", dependencies);
}
export function registerDirectEvent(
registrationName: string,
dependencies: Array<DOMEventName>
) {
registrationNameDependencies[registrationName] = dependencies;
for (let i = 0; i < dependencies.length; i++) {
allNativeEvents.add(dependencies[i]);
}
}
// DOMPluginEventSystem.js
function dispatchEventsForPlugins(
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
nativeEvent: AnyNativeEvent,
targetInst: null | Fiber,
targetContainer: EventTarget
): void {
const nativeEventTarget = getEventTarget(nativeEvent);
const dispatchQueue: DispatchQueue = [];
extractEvents(
dispatchQueue,
domEventName,
targetInst,
nativeEvent,
nativeEventTarget,
eventSystemFlags,
targetContainer
);
processDispatchQueue(dispatchQueue, eventSystemFlags);
}
export function processDispatchQueue(
dispatchQueue: DispatchQueue,
eventSystemFlags: EventSystemFlags
): void {
const inCapturePhase = (eventSystemFlags & IS_CAPTURE_PHASE) !== 0;
for (let i = 0; i < dispatchQueue.length; i++) {
const { event, listeners } = dispatchQueue[i];
processDispatchQueueItemsInOrder(event, listeners, inCapturePhase);
// event system doesn't use pooling.
}
// This would be a good time to rethrow if any of the event handlers threw.
rethrowCaughtError();
}
// ReactDOMEventListener.js
// dispatchEventForPluginEventSystem、
// createEventListenerWrapperWithPriority方法中注册事件回调的函数,
// 还记得事件的优先级么?
//离散事件优先级 click onchange
export const DiscreteEventPriority = SyncLane; //1
//连续事件的优先级 mousemove
export const ContinuousEventPriority = InputContinuousLane; //4
//默认事件车道
export const DefaultEventPriority = DefaultLane; //16
//空闲事件优先级
export const IdleEventPriority = IdleLane; //
export function createEventListenerWrapperWithPriority(
targetContainer: EventTarget,
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
): Function {
const eventPriority = getEventPriority(domEventName);
let listenerWrapper;
switch (eventPriority) {
case DiscreteEventPriority:
listenerWrapper = dispatchDiscreteEvent;
break;
case ContinuousEventPriority:
listenerWrapper = dispatchContinuousEvent;
break;
case DefaultEventPriority:
default:
listenerWrapper = dispatchEvent;
break;
}
return listenerWrapper.bind(
null,
domEventName,
eventSystemFlags,
targetContainer,
);
}
function dispatchDiscreteEvent(
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
container: EventTarget,
nativeEvent: AnyNativeEvent,
) {
const previousPriority = getCurrentUpdatePriority();
const prevTransition = ReactCurrentBatchConfig.transition;
ReactCurrentBatchConfig.transition = null;
try {
setCurrentUpdatePriority(DiscreteEventPriority);
dispatchEvent(domEventName, eventSystemFlags, container, nativeEvent);
} finally {
setCurrentUpdatePriority(previousPriority);
ReactCurrentBatchConfig.transition = prevTransition;
}
}
export function dispatchEvent(
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
targetContainer: EventTarget,
nativeEvent: AnyNativeEvent,
): void {
if (!_enabled) {
return;
}
dispatchEventOriginal(
domEventName,
eventSystemFlags,
targetContainer,
nativeEvent,
);
}
// 执行
if (blockedOn === null) {
dispatchEventForPluginEventSystem(
domEventName,
eventSystemFlags,
nativeEvent,
return_targetInst,
targetContainer,
);
if (allowReplay) {
clearIfContinuousEvent(domEventName, nativeEvent);
}
return;
}
// extractEvents中存储事件
processDispatchQueue(dispatchQueue, eventSystemFlags);
/** + * 处理dispatch方法
+ * @param {*} event 合成事件对象
+ * @param {*} dispatchListeners 监听函数
+ * @param {*} inCapturePhase 是否是获取阶段
+ */
// processDispatchQueueItemsInOrder处理冒泡或者捕捉
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;
}
executeDispatch(event, listener, currentTarget);
previousInstance = instance;
}
} else {
for (let i = 0; i < dispatchListeners.length; i++) {
const {instance, currentTarget, listener} = dispatchListeners[i];
if (instance !== previousInstance && event.isPropagationStopped()) {
return;
}
executeDispatch(event, listener, currentTarget);
previousInstance = instance;
}
}
}
另外在 React 事件系统中还有其他事件监听,大家感兴趣可以去了解源码,这些方法的作用如下:
listenToNativeEvent:监听原生 DOM 事件,可以用于处理自定义组件中的原生事件。 listenToNonDelegatedEvent:监听非委托事件(即不冒泡的事件)。 listenToNativeEventForNonManagedEventTarget:为非受控事件目标添加原生事件监听器,例如在自定义组件内部使用的第三方库。 listenToAllSupportedEvents:监听组件支持的所有事件。
阅读量:2021
点赞量:0
收藏量:0