import { Fiber } from '../../react-reconciler/ReactInternalTypes' ; import { HostComponent } from '../../react-reconciler/ReactWorkTags' ; import { DOMEventName } from './DOMEventNames' ; import { addEventBubbleListener , addEventBubbleListenerWithPassiveFlag , addEventCaptureListener , addEventCaptureListenerWithPassiveFlag , } from './EventListener' ; import { allNativeEvents } from './EventRegistry' ; import { EventSystemFlags , IS_CAPTURE_PHASE , SHOULD_NOT_PROCESS_POLYFILL_EVENT_PLUGINS , } from './EventSystemFlags' ; import { getEventTarget } from './getEventTarget' ; import { getListener } from './getListener' ; import { AnyNativeEvent } from './PluginModuleType' ; import * as SimpleEventPlugin from './plugins/SimpleEventPlugin' ; import * as ChangeEventPlugin from './plugins/ChangeEventPlugin' ; import { createEventListenerWrapperWithPriority } from './ReactDOMEventListener' ; import { ReactSyntheticEvent } from './ReactSyntheticEventType' ; import { batchedEventUpdates } from '../../react-reconciler/ReactFiberReconciler' ; const listeningMarker = '_reactListening' + Math . random ( ) . toString ( 36 ) . slice ( 2 ) ; type DispatchListener = { instance : Fiber | null ; listener : Function ; currentTarget : EventTarget ; } ; type DispatchEntry = { event : ReactSyntheticEvent ; listeners : DispatchListener [ ] ; } ; export type DispatchQueue = DispatchEntry [ ] ; SimpleEventPlugin . registerEvents ( ) ; ChangeEventPlugin . registerEvents ( ) ; /**
 * 我们不因该在container代理这些事件，而是因该把他们添加到真正的目标dom上
 * 主要是因为这些事件的冒泡不具有一致性
 */ export const nonDelegatedEvents = new Set ( [ 'cancel' as DOMEventName , 'close' as DOMEventName , 'invalid' as DOMEventName , 'load' as DOMEventName , 'scroll' as DOMEventName , 'toggle' as DOMEventName , ] ) ; const addTrappedEventListener = ( targetContainer , domEventName , eventSystemFlags , isCapturePhaseListener ) => { const listener = createEventListenerWrapperWithPriority ( targetContainer , domEventName , eventSystemFlags ) ; let isPassiveListener = undefined ; if ( domEventName === 'wheel' || domEventName === 'touchmove' || domEventName === 'touchstart' ) { isPassiveListener = true ; } let unsubscribeListener ; if ( isCapturePhaseListener ) { if ( isPassiveListener !== undefined ) { unsubscribeListener = addEventCaptureListenerWithPassiveFlag ( targetContainer , domEventName , listener , isPassiveListener ) ; } else { unsubscribeListener = addEventCaptureListener ( targetContainer , domEventName , listener ) ; } } else { if ( isPassiveListener !== undefined ) { unsubscribeListener = addEventBubbleListenerWithPassiveFlag ( targetContainer , domEventName , listener , isPassiveListener ) ; } else { unsubscribeListener = addEventBubbleListener ( targetContainer , domEventName , listener ) ; } } } ; param domEventName param isCapturePhaseListener param target const listenToNativeEvent = ( domEventName , isCapturePhaseListener , target ) => { let eventSystemFlags = 0 ; if ( isCapturePhaseListener ) { eventSystemFlags |= IS_CAPTURE_PHASE ; } addTrappedEventListener ( target , domEventName , eventSystemFlags , isCapturePhaseListener ) ; } ; param rootContainerElement export const listenToAllSupportedEvents = ( rootContainerElement ) => { if ( ! ( rootContainerElement as any ) [ listeningMarker ] ) { allNativeEvents . forEach ( ( domEventName ) => { /**
             * 单独处理selectionchange因为他不会冒泡，而且需要设置在document上
             */ if ( domEventName !== 'selectionchange' ) { if ( ! nonDelegatedEvents . has ( domEventName ) ) { listenToNativeEvent ( domEventName , false , rootContainerElement ) ; } listenToNativeEvent ( domEventName , true , rootContainerElement ) ; } } ) ; } } ; const extractEvents = ( dispatchQueue , domEventName , targetInst , nativeEvent , nativeEventTarget , eventSystemFlags , targetContainer ) => { SimpleEventPlugin . extractEvents ( dispatchQueue , domEventName , targetInst , nativeEvent , nativeEventTarget , eventSystemFlags , targetContainer ) ; const shouldProcessPolyfillPlugins = ( eventSystemFlags & SHOULD_NOT_PROCESS_POLYFILL_EVENT_PLUGINS ) === 0 ; if ( shouldProcessPolyfillPlugins ) { ChangeEventPlugin . extractEvents ( dispatchQueue , domEventName , targetInst , nativeEvent , nativeEventTarget , eventSystemFlags , targetContainer ) ; } } ; const createDispatchListener = ( instance , listener , currentTarget ) : DispatchListener => { return { instance , listener , currentTarget , } ; } ; export const accumulateTwoPhaseListeners = ( targetFiber , reactName ) : DispatchListener [ ] => { const captureName = reactName + 'Capture' ; const listeners = [ ] ; let instance = targetFiber ; while ( instance !== null ) { const { stateNode , tag } = instance ; if ( tag === HostComponent && stateNode !== null ) { const currentTarget = stateNode ; const captureListener = getListener ( instance , captureName ) ; if ( captureListener !== null ) { listeners . unshift ( createDispatchListener ( instance , captureListener , currentTarget ) ) ; } const bubbleListener = getListener ( instance , reactName ) ; if ( bubbleListener !== null ) { listeners . push ( createDispatchListener ( instance , bubbleListener , currentTarget ) ) ; } } instance = instance . return ; } return listeners ; } ; export const accumulateSinglePhaseListeners = ( targetFiber , reactName , inCapturePhase , accumulateTargetOnly ) => { const captureName = reactName !== null ? reactName + 'Capture' : null ; const reactEventName = inCapturePhase ? captureName : reactName ; let listeners = [ ] ; let instance = targetFiber ; let lastHostComponent = null ; while ( instance !== null ) { const { tag , stateNode } = instance ; if ( tag === HostComponent && stateNode !== null ) { lastHostComponent = stateNode ; if ( reactEventName !== null ) { const listener = getListener ( instance , reactEventName ) ; if ( listener !== null ) { listeners . push ( createDispatchListener ( instance , listener , lastHostComponent ) ) ; } } } if ( accumulateTargetOnly ) break ; instance = instance . return ; } return listeners ; } ; const executeDispatch = ( event , listener , currentTarget ) : void => { listener ( event ) ; } ; const processDispatchQueueItemsInOrder = ( event , dispatchListeners , inCapturePhase ) : void => { if ( inCapturePhase ) { for ( let i = dispatchListeners . length - 1 ; i >= 0 ; -- i ) { const { instance , currentTarget , listener } = dispatchListeners [ i ] ; executeDispatch ( event , listener , currentTarget ) ; } } else { for ( let i = 0 ; i < dispatchListeners . length ; ++ i ) { const { instance , currentTarget , listener } = dispatchListeners [ i ] ; executeDispatch ( event , listener , currentTarget ) ; } } } ; export const processDispatchQueue = ( dispatchQueue , 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 ) ; } } ; const dispatchEventsForPlugins = ( domEventName , eventSystemFlags , nativeEvent , targetInst , targetContainer ) => { const nativeEventTarget = getEventTarget ( nativeEvent ) ; const dispatchQueue = [ ] ; extractEvents ( dispatchQueue , domEventName , targetInst , nativeEvent , nativeEventTarget , eventSystemFlags , targetContainer ) ; processDispatchQueue ( dispatchQueue , eventSystemFlags ) ; } ; export const dispatchEventForPluginEventSystem = ( domEventName , eventSystemFlags , nativeEvent , targetInst , targetContainer ) => { const ancestorInst = targetInst ; batchedEventUpdates ( ( ) => dispatchEventsForPlugins ( domEventName , eventSystemFlags , nativeEvent , ancestorInst , targetContainer ) , null ) ; } ;