事件模块的注入模式
React 为了跨平台,对于事件体系的代码做出了一些妥协,采用动态注入的方式让不同的平台对事件核心模块进行插件注入。我们先来看ReactDOM的入口文件,里面有这么一句代码:import './ReactDOMClientInjection';,这就是注入的开始,这个 js 的代码如下:
import * as EventPluginHub from 'events/EventPluginHub'
import * as EventPluginUtils from 'events/EventPluginUtils'
import {
getFiberCurrentPropsFromNode,
getInstanceFromNode,
getNodeFromInstance,
} from './ReactDOMComponentTree'
import BeforeInputEventPlugin from '../events/BeforeInputEventPlugin'
import ChangeEventPlugin from '../events/ChangeEventPlugin'
import DOMEventPluginOrder from '../events/DOMEventPluginOrder'
import EnterLeaveEventPlugin from '../events/EnterLeaveEventPlugin'
import SelectEventPlugin from '../events/SelectEventPlugin'
import SimpleEventPlugin from '../events/SimpleEventPlugin'
EventPluginHub.injection.injectEventPluginOrder(DOMEventPluginOrder)
EventPluginUtils.setComponentTree(
getFiberCurrentPropsFromNode,
getInstanceFromNode,
getNodeFromInstance,
)
EventPluginHub.injection.injectEventPluginsByName({
SimpleEventPlugin: SimpleEventPlugin,
EnterLeaveEventPlugin: EnterLeaveEventPlugin,
ChangeEventPlugin: ChangeEventPlugin,
SelectEventPlugin: SelectEventPlugin,
BeforeInputEventPlugin: BeforeInputEventPlugin,
})
通过这两个方法向事件系统注入了平台相关的事件代码,同时确定事件的调用顺序。
plugin
我们先来看一下一个plugin应该长咋样:
const ChangeEventPlugin = {
eventTypes: {
change: {
phasedRegistrationNames: {
bubbled: 'onChange',
captured: 'onChangeCapture',
},
isInteractive: boolean, // 标志是否高优先级反馈
registrationName: string,
dependencies: [
TOP_BLUR,
TOP_CHANGE,
TOP_CLICK,
TOP_FOCUS,
TOP_INPUT,
TOP_KEY_DOWN,
TOP_KEY_UP,
TOP_SELECTION_CHANGE,
],
},
},
_isInputEventSupported: isInputEventSupported,
extractEvents: function(
topLevelType,
targetInst,
nativeEvent,
nativeEventTarget,
) {
// 创建event对象并return
},
}
eventTypes是以具体事件为key的 map 对象,其中每个事件的phasedRegistrationNames是指定props的名字,dependencies是如果需要绑定change事件需要同时绑定哪些事件
extractEvents是一个方法,用来根据具体真实触发的事件类型等参数,返回对应的事件对象,也可以返回null表示当前事件跟这个插件没有关系。
注册插件
| 变量名 | 作用 |
|---|---|
eventPluginOrder |
记录插件的调用顺序 |
namesToPlugins |
以插件名为key的插件 map |
plugins |
按照eventPluginOrder顺序存储的插件模块数组 |
eventNameDispatchConfigs |
按照每个插件中的eventTypes中的每一项为key,其对应的对象为value的对象 |
registrationNameModules |
存储有phasedRegistrationNames或者registrationName的插件的事件对应的模块 |
首先调用injectEventPluginOrder,设置eventPluginOrder
然后调用injectEventPluginsByName,把所有插件加入到namesToPlugins对象中,并以插件名为key
然后调用recomputePluginOrdering把所有插件安顺序插入到plugins数组中,并对每个插件中的eventTypes中的每个事件类型调用publishEventForPlugin,设置eventNameDispatchConfigs对象,以事件名为key存储dispatchConfig,也就是上面插件中的eventTypes.change对应的对象
然后还需要对每一个phasedRegistrationNames里面的项执行publishRegistrationName,设置registrationNameModules,以事件名为key存储模块,同时设置registrationNameDependencies,以事件名为key存储事件的dependencies
registrationNameModules在更新 DOM 节点的时候会被用到,registrationNameDependencies在绑定事件的使用会被用到。
整个注册过程就是为了初始化设置这些变量,这些变量在后续的 DOM 操作中会扮演比较重要的角色。
结构
eventNameDispatchConfigs
{
change: ChangePlugin.eventTypes.change,
// ...other plugins
}
registrationNameModules
{
onChange: ChangePlugin,
onChangeCapture: ChangePlugin
}
registrationNameDependencies
{
onChange: ChangePlugin.eventTypes.change.dependencies,
onChangeCapture: ChangePlugin.eventTypes.change.dependencies
}
results matching ""
No results matching ""
扫码添加Jokcy,更多更新更优质的前端学习内容不断更新中,期待与你一起成长!