runEventQueuelnBatch(events)做了兩件事
執行的細節如下:
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 合成事件分為兩個步驟:
其實在 EventPluginHub.js 里主要做了兩件事情.
1.從event._dispatchListener 取出 dispatchlistener,然后dispatch事件,
循環_dispatchListeners,調用executeDispatch,然后走到ReactErrorUtils.invokeGuardedCallback;
2.釋放 event
上面這個函數最重要的功能就是將事件對應的dom元素綁定到了currentTarget上,
這樣我們通過e.currentTarget就可以找到綁定事件的原生dom元素。
下面就是整個執行過程的尾聲了:
ReactErrorUtils.js
var fakeNode = document.createElement('react'); ReactErrorUtils.invokeGuardedCallback = function(name, func, a, b) { var boundFunc = func.bind(null, a, b); var evtType = `react-${name}`; fakeNode.addEventListener(evtType, boundFunc, false); var evt = document.createEvent('Event'); evt.initEvent(evtType, false, false); fakeNode.dispatchEvent(evt); fakeNode.removeEventListener(evtType, boundFunc, false); };
由invokeGuardedCallback可知,最后react調用了faked元素的dispatchEvent方法來觸發事件,并且觸發完畢之后立即移除監聽事件。
總的來說,整個click事件被分發的過程就是:
1、用EventPluginHub生成合成事件,這里注意同一事件類型只會生成一個合成事件,里面的_dispatchListeners里儲存了同一事件類型的所有回調函數
2、按順序去執行它
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com