著有《React 源码》《React 用到的一些算法》《javascript地月星》等多个专栏。欢迎关注。
文章不好写,要是有帮助别忘了点赞,收藏,评论 ~你的鼓励是我继续挖干货的动力🔥。
另外,本文为原创内容,商业转载请联系作者获得授权,非商业转载需注明出处,感谢理解~
总流程
事件系统的设计原理:
React采用事件委托机制,所有可以被委托的事件都委托到DOM容器上。(少数不能委托的事件,需要绑定在元素本身。)
虽然React采用的是事件委托,但具体的事件、事件回调函数是写在各个Fiber节点上的,后续还需要事件收集。
listenToAllSupportedEvents
给容器绑定统一的事件监听器。容器有两种类型tag=HostRoot以及tag=HostPortal,它们的container。
// HostRoot
function createRoot(container, options) {
...
var rootContainerElement = container.nodeType === COMMENT_NODE ? container.parentNode : container;
listenToAllSupportedEvents(rootContainerElement);//#rootA #rootB #modal-container
return new ReactDOMRoot(root);
}
// HostPortal
function preparePortalMount(portalInstance) {
listenToAllSupportedEvents(portalInstance);
}
function completeWork(current, workInProgress, renderLanes) {
switch (workInProgress.tag) {
...
case HostPortal:
popHostContainer(workInProgress);
updateHostContainer(current, workInProgress);
if (current === null) {
preparePortalMount(workInProgress.stateNode.containerInfo); //给HostPortal的容器添加事件,绑定dispatchEventForPluginEventSystem
}
bubbleProperties(workInProgress);
return null;
}
}
var listeningMarker = '_reactListening' + Math.ranDOM().toString(36).slice(2);
function listenToAllSupportedEvents(rootContainerElement) {
if (!rootContainerElement[listeningMarker]) {
rootContainerElement[listeningMarker] = true;
//包含了所有可以委托的事件
allNativeEvents.forEach(function (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);
}
//包含了dispatchEventForPluginEventSystem
listenToNativeEvent(DOMEventName, true, rootContainerElement);
}
});
var ownerDocument = rootContainerElement.nodeType === DOCUMENT_NODE ? rootContainerElement : rootContainerElement.ownerDocument;
if (ownerDocument !== null) {
// The selectionchange event also needs deduplication
// but it is attached to the document.
if (!ownerDocument[listeningMarker]) {
ownerDocument[listeningMarker] = true;
listenToNativeEvent('selectionchange', false, ownerDocument);
}
}
}
}