//这就是核心的处理了 handleTopLevel: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { //返回合成事件 //这里进入了EventPluginHub,调用事件插件方法,返回合成事件,并执行队列里的dispatchListener var events = EventPluginHub.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); //执行合成事件 runEventQueueInBatch(events); }
合成事件如何生成,请看上方事件触发的流程图runEventQueuelnBatch(events)做了两件事
把 dispatchListener里面的事件排队push进 eventQueue
执行 EventPluginHub.processEventQueue(false);
执行的细节如下:
EventPluginHub.js
// 循环 eventQueue调用 var executeDispatchesAndReleaseTopLevel = function (e) { return executeDispatchesAndRelease(e, false); }; /* 从event._dispatchListener 取出 dispatchlistener,然后dispatch事件, * 循环_dispatchListeners,调用executeDispatch */ var executeDispatchesAndRelease = function (event, simulated) { if (event) { // 在这里dispatch事件 EventPluginUtils.executeDispatchesInOrder(event, simulated); // 释放事件 if (!event.isPersistent()) { event.constructor.release(event); } } }; enqueueEvents: function (events) { if (events) { eventQueue = accumulateInto(eventQueue, events); } }, /** * Dispatches all synthetic events on the event queue. * * @internal */ processEventQueue: function (simulated) { // Set `eventQueue` to null before processing it so that we can tell if more // events get enqueued while processing. var processingEventQueue = eventQueue; eventQueue = null; if (simulated) { forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseSimulated); } else { forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); } // This would be a good time to rethrow if any of the event fexers threw. ReactErrorUtils.rethrowCaughtError(); }, /** * Standard/simple iteration through an event's collected dispatches. */ function executeDispatchesInOrder(event, simulated) { var dispatchListeners = event._dispatchListeners; var dispatchInstances = event._dispatchInstances; if (Array.isArray(dispatchListeners)) { for (var i = 0; i < dispatchListeners.length; i++) { // 由这里可以看出,合成事件的stopPropagation只能阻止react合成事件的冒泡, // 因为event._dispatchListeners 只记录了由jsx绑定的绑定的事件,对于原生绑定的是没有记录的 if (event.isPropagationStopped()) { break; } // Listeners and Instances are two parallel arrays that are always in sync. executeDispatch(event, simulated, dispatchListeners[i], dispatchInstances[i]); } } else if (dispatchListeners) { executeDispatch(event, simulated, dispatchListeners, dispatchInstances); } event._dispatchListeners = null; event._dispatchInstances = null; } function executeDispatch(event, simulated, listener, inst) { var type = event.type || 'unknown-event'; // 注意这里将事件对应的dom元素绑定到了currentTarget上 event.currentTarget = EventPluginUtils.getNodeFromInstance(inst); if (simulated) { ReactErrorUtils.invokeGuardedCallbackWithCatch(type, listener, event); } else { // 一般都是非模拟的情况,执行invokeGuardedCallback ReactErrorUtils.invokeGuardedCallback(type, listener, event); } event.currentTarget = null; }
由上面的函数可知,dispatch 合成事件分为两个步骤:
通过_dispatchListeners里得到所有绑定的回调函数,在通过_dispatchInstances的绑定回调函数的虚拟dom元素
循环执行_dispatchListeners里所有的回调函数,这里有一个特殊情况,也是react阻止冒泡的原理
其实在 EventPluginHub.js 里主要做了两件事情.