## react源码解析18事件系统 #### 视频课程(高效学习):[进入课程](https://xiaochen1024.com/series/60b1b600712e370039088e24/60b1b636712e370039088e25) #### 课程目录: [1.开篇介绍和面试题](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b311cf10a4003b634719) [2.react的设计理念](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b31ccf10a4003b63471a) [3.react源码架构](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b328cf10a4003b63471b) [4.源码目录结构和调试](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b32ecf10a4003b63471c) [5.jsx&核心api](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b334cf10a4003b63471d) [6.legacy和concurrent模式入口函数](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b33acf10a4003b63471e) [7.Fiber架构](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b340cf10a4003b63471f) [8.render阶段](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b348cf10a4003b634720) [9.diff算法](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b354cf10a4003b634721) [10.commit阶段](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b360cf10a4003b634722) [11.生命周期](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b367cf10a4003b634723) [12.状态更新流程](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b36ecf10a4003b634724) [13.hooks源码](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b374cf10a4003b634725) [14.手写hooks](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b37acf10a4003b634726) [15.scheduler&Lane](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b556cf10a4003b634727) [16.concurrent模式](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b55ccf10a4003b634728) [17.context](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b564cf10a4003b634729) [18事件系统](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b56ccf10a4003b63472a) [19.手写迷你版react](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b57bcf10a4003b63472b) [20.总结&第一章的面试题解答](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b581cf10a4003b63472c) [21.demo](https://xiaochen1024.com/courseware/60b1b2f6cf10a4003b634718/60b1b587cf10a4003b63472d) #### 从一个bug说起 下面这个demo_13在react17和react16中有什么不同吗?代码也很简单,模拟一个modal框,点击显示出现,点击其他地方,相当于点击了mask,modal消失,因为react事件都是委托到上层,所以需要在handleClick阻止冒泡,这样点击显示的时候不会触发document上的事件回调,导致modal无法显示。但是在react16上发现这样做还是不行,需要调用e.nativeEvent.stopImmediatePropagation()才能实现,而react17上没什么影响 究其原因就是react16和17在委托事件的容器上做出了改变,react16的事件会冒泡的document上,而17则会冒泡到root容器上,也就是ReactDom.render的第二个参数 ```js export default class Demo13 extends React.Component { state = { show: false }; componentDidMount() { document.addEventListener("click", () => { this.setState({ show: false }); }); } handleClick = (e) => { e.stopPropagation();//react17中生效 // e.nativeEvent.stopImmediatePropagation(); //react16中生效 stopImmediatePropagation也阻止本级监听函数执行 this.setState({ show: true }); }; render() { return (
{this.state.show &&
); } } ``` 大家也可以看下demo_11、demo_12在react16、17触发顺序有何差异,同时demo项目中的event.html也模拟了react16、17的事件代理机制 #### 事件系统架构图  我们以SimpleEvent为例看事件注册、绑定和触发的过程,看视频的调试过程 #### 事件注册 1. DOMPluginEventSystem.js会调用SimpleEventPlugin插件的registerEvents方法注册事件 ```js //DOMPluginEventSystem.js SimpleEventPlugin.registerEvents(); ``` 2. registerSimpleEvents ```js function registerSimpleEvents() { registerSimplePluginEventsAndSetTheirPriorities(discreteEventPairsForSimpleEventPlugin, DiscreteEvent); //... } function registerSimplePluginEventsAndSetTheirPriorities(eventTypes, priority) { for (var i = 0; i < eventTypes.length; i += 2) { var topEvent = eventTypes[i]; var event = eventTypes[i + 1]; var capitalizedEvent = event[0].toUpperCase() + event.slice(1); var reactName = 'on' + capitalizedEvent; eventPriorities.set(topEvent, priority); topLevelEventsToReactNames.set(topEvent, reactName); registerTwoPhaseEvent(reactName, [topEvent]);//注册捕获和冒泡两个阶段的事件 } } ``` 3. registerTwoPhaseEvent ```js function registerTwoPhaseEvent(registrationName, dependencies) { registerDirectEvent(registrationName, dependencies); registerDirectEvent(registrationName + 'Capture', dependencies); } ``` 4. registerDirectEvent ```js function registerDirectEvent(registrationName, dependencies) { //... for (var i = 0; i < dependencies.length; i++) { allNativeEvents.add(dependencies[i]);//生成allNativeEvents对象 } } ``` #### 事件绑定 1. listenToAllSupportedEvents ```js //由函数createRootImpl调用,也就是在创建根节点之后执行 function listenToAllSupportedEvents(rootContainerElement) { allNativeEvents.forEach(function (domEventName) { if (!nonDelegatedEvents.has(domEventName)) { listenToNativeEvent(domEventName, false, rootContainerElement, null); } listenToNativeEvent(domEventName, true, rootContainerElement, null); }); } } ``` 2. listenToNativeEvent ```js function listenToNativeEvent(domEventName, isCapturePhaseListener, rootContainerElement, targetElement) { //... if (!listenerSet.has(listenerSetKey)) { if (isCapturePhaseListener) { eventSystemFlags |= IS_CAPTURE_PHASE; } addTrappedEventListener(target, domEventName, eventSystemFlags, isCapturePhaseListener); listenerSet.add(listenerSetKey); } } ``` 3. addTrappedEventListener ```js function addTrappedEventListener(targetContainer, domEventName, eventSystemFlags, isCapturePhaseListener, isDeferredListenerForLegacyFBSupport) { //创建具有优先级的监听函数 var listener = createEventListenerWrapperWithPriority(targetContainer, domEventName, eventSystemFlags); //... targetContainer = targetContainer; var 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); } } } ``` 4. createEventListenerWrapperWithPriority ```js function createEventListenerWrapperWithPriority(targetContainer, domEventName, eventSystemFlags) { var eventPriority = getEventPriorityForPluginSystem(domEventName); var listenerWrapper; switch (eventPriority) { case DiscreteEvent: listenerWrapper = dispatchDiscreteEvent; break; case UserBlockingEvent: listenerWrapper = dispatchUserBlockingUpdate; break; case ContinuousEvent: default: listenerWrapper = dispatchEvent; break; } //绑定dispatchDiscreteEvent return listenerWrapper.bind(null, domEventName, eventSystemFlags, targetContainer); } ``` #### 事件触发 1. dispatchDiscreteEvent(dispatchEvent) ```js function dispatchDiscreteEvent(domEventName, eventSystemFlags, container, nativeEvent) { { flushDiscreteUpdatesIfNeeded(nativeEvent.timeStamp); } discreteUpdates(dispatchEvent, domEventName, eventSystemFlags, container, nativeEvent); } ``` 2. unstable_runWithPriority ```js function unstable_runWithPriority(priorityLevel, eventHandler) {//eventHandler就是dispatchEvent函数 switch (priorityLevel) { case ImmediatePriority: case UserBlockingPriority: case NormalPriority: case LowPriority: case IdlePriority: break; default: priorityLevel = NormalPriority; } var previousPriorityLevel = currentPriorityLevel; currentPriorityLevel = priorityLevel; try { return eventHandler(); } finally { currentPriorityLevel = previousPriorityLevel; } } ``` 3. batchedEventUpdates ```js function batchedEventUpdates(fn, a, b) { if (isBatchingEventUpdates) { return fn(a, b); } isBatchingEventUpdates = true; try { return batchedEventUpdatesImpl(fn, a, b); //fn参数即: //function () { // return dispatchEventsForPlugins(domEventName, eventSystemFlags, nativeEvent, //ancestorInst); //} function () { return dispatchEventsForPlugins(domEventName, eventSystemFlags, nativeEvent, ancestorInst); } } finally { isBatchingEventUpdates = false; finishEventHandler(); } } ``` 4. dispatchEventsForPlugins ```js function dispatchEventsForPlugins(domEventName, eventSystemFlags, nativeEvent, targetInst, targetContainer) { var nativeEventTarget = getEventTarget(nativeEvent); var dispatchQueue = []; //extractEvent生成SyntheticEvent extractEvents(dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags); //processDispatchQueue执行形成事件队列 processDispatchQueue(dispatchQueue, eventSystemFlags); } ```
e.nativeEvent.stopImmediatePropagation()}>modal
}
微信关注我们
原文链接:https://blog.51cto.com/u_11890769/2939858
转载内容版权归作者及来源网站所有!
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
相关文章
发表评论
资源下载
更多资源优质分享Android(本站安卓app)
近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。
Apache Tomcat7、8、9(Java Web服务器)
Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。
Java Development Kit(Java开发工具)
JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。
Sublime Text 一个代码编辑器
Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。