# 关于React事件的疑问
-
1.为什么要手动绑定
this -
2.
React事件和原生事件有什么区别 -
3.
React事件和原生事件的执行顺序,可以混用吗 -
4.
React事件如何解决跨浏览器兼容 -
5.什么是合成事件
下面是我阅读过源码后,将所有的执行流程总结出来的流程图,不会贴代码,如果你想阅读代码看看具体是如何实现的,可以根据流程图去源码里寻找。
# 事件注册

- 组件装载 / 更新。
- 通过
lastProps、nextProps判断是否新增、删除事件分别调用事件注册、卸载方法。 - 调用
EventPluginHub的enqueuePutListener进行事件存储 - 获取
document对象。 - 根据事件名称(如
onClick、onCaptureClick)判断是进行冒泡还是捕获。 - 判断是否存在
addEventListener方法,否则使用attachEvent(兼容IE)。 - 给
document注册原生事件回调为dispatchEvent(统一的事件分发机制)。
# 事件存储

EventPluginHub负责管理React合成事件的callback,它将callback存储在listenerBank中,另外还存储了负责合成事件的Plugin。EventPluginHub的putListener方法是向存储容器中增加一个listener。- 获取绑定事件的元素的唯一标识
key。 - 将
callback根据事件类型,元素的唯一标识key存储在listenerBank中。 listenerBank的结构是:listenerBank[registrationName][key]。
例如:
{
onClick:{
nodeid1:()=>{...}
nodeid2:()=>{...}
},
onChange:{
nodeid3:()=>{...}
nodeid4:()=>{...}
}
}
@前端进阶之旅: 代码已经复制到剪贴板
# 事件触发 / 执行

这里的事件执行利用了React的批处理机制,在前一篇的【React深入】setState执行机制中已经分析过,这里不再多加分析。
- 触发
document注册原生事件的回调dispatchEvent - 获取到触发这个事件最深一级的元素
例如下面的代码:首先会获取到this.child
<div onClick={this.parentClick} ref={ref => this.parent = ref}>
<div onClick={this.childClick} ref={ref => this.child = ref}>
test
</div>
</div>
@前端进阶之旅: 代码已经复制到剪贴板
- 遍历这个元素的所有父元素,依次对每一级元素进行处理。
- 构造合成事件。
- 将每一级的合成事件存储在
eventQueue事件队列中。 - 遍历
eventQueue。 - 通过
isPropagationStopped判断当前事件是否执行了阻止冒泡方法。 - 如果阻止了冒泡,停止遍历,否则通过
executeDispatch执行合成事件。 - 释放处理完成的事件。
react在自己的合成事件中重写了stopPropagation方法,将isPropagationStopped设置为true,然后在遍历每一级事件的过程中根据此遍历判断是否继续执行。这就是react自己实现的冒泡机制。
# 合成事件

- 调用
EventPluginHub的
