🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## DOM 事件 ### DOM 事件流 * 捕获阶段 * 目标阶段 * 冒泡阶段 ![](https://img.kancloud.cn/00/76/0076d7e0cee2305c6b66dd32979f0c2a_2493x1313.png) ### 阻止冒泡 * cancelBubble * stopPropagation ``` function stopPropagation( event ) { // IE if( !event ){ window.event.cancelBubble = true } if( event.stopPropagation ){ event.stopPropagation() } } ``` ## 阻止事件默认行为 * returnValue * preventDefault ``` function preventDefault( event ) { // IE if( !event ){ window.event.returnValue = true } if( event.preventDefault ){ event.preventDefault() } } ``` ### 事件代理 * 也就是事件委托, 委托给父元素进行事件监听 * 利用事件冒泡来实现 * 能够减少事件注册,节省内存 ![](https://img.kancloud.cn/92/4d/924d83b6098f35f6f6f7fe94396b214c_1229x624.png) ## react 事件机制 * 事件注册 * 事件绑定 * 事件触发 ### 事件注册 我们先提出以下疑问: * [ ] onClick 是如何注册到React事件系统中的? * [ ] 原生事件 click 和 合成事件 onClick 是如何对应起来的? * [ ] 事件注册到哪里? 1. react 一开始就把事件委托到根节点上去了 ![](https://img.kancloud.cn/74/8a/748a2445a9681d60e80bb2e1bf25c97c_1712x1131.png) **绑定前的疑问**🤔️ * 所有支持的事件是什么事件 * 这些事件是在哪里定义的,是用户传入的吗 ![](https://img.kancloud.cn/ff/3c/ff3c2f30fa43e365ec3a4b09d070d18a_3019x1471.png) #### 总结 1. onClick 是如何注册到React事件系统中的? 在事件注册时,注册的是原生事件,不是合成事件,onClick 属于合成事件 ![](https://img.kancloud.cn/bc/c0/bcc0f8dd37021bf2a59a9d89ec8f9bea_1102x544.png) 2. 原生事件 click 和 合成事件 onClick 是如何对应起来的? 在 react 事件注册时,react 提供了一个数组 discreteEventPairsForSimpleEventPlugin,存储了简单事件,遍历discreteEventPairsForSimpleEventPlugin,生成合成事件名(onClick),存储在一个 Map 集合中 ![](https://img.kancloud.cn/15/03/15038eda630c88dffa6b55738f6187fc_2234x116.png) ![](https://img.kancloud.cn/a7/d8/a7d802f73c580e16ea7f37b5d6683b6d_1597x641.png) 3. 所有支持的事件 ![](https://img.kancloud.cn/2d/7d/2d7d90c4fd6c899afe7787cc43cf03aa_1058x1091.png) 4. 事件注册在 v17 之前是绑定在 document 上的,在 v17 改成了 app 容器上 ### 事件绑定 * 判断需要代理和不需要代理(cancel、close、load)的事件 * 需要代理的事件,绑定捕获和冒泡 * 不需要代理的事件,只绑定捕获事件 * 对这些事件使用 addEventListener 进行事件绑定 ![](https://img.kancloud.cn/ac/5f/ac5f95f0d4ea5f0dfcb4d3947c1ef904_1701x735.png) ### 事件触发 * [ ] 合成事件 onClick存在哪里,是如何被触发的?😌 ![](https://img.kancloud.cn/7a/2c/7a2cbbf6f9b8228f73d58955f22e478d_2307x1601.png) Fiber树: ![](https://img.kancloud.cn/96/4f/964f4e842f729769ee768f8b1aeab176_1680x1087.png) #### 总结: 1. 合成事件函数 handleDivClick ,handleDivClickCapture 存在对应 DOM 元素类型 fiber 对象中。 ![](https://img.kancloud.cn/2c/e3/2ce3ed82115e74762b6988b8fc7583df_1458x894.png) 2. fiber 对象和dom的关系 ![](https://img.kancloud.cn/b7/93/b793f4fcb6273d437676a8ad03226181_1357x401.png) ## 合成事件 * 兼容不同浏览器 * 跨端和服务端渲染 * 支持冒泡 ### 对于合成的理解 1. 对原生事件的封装 ( e 不是原生事件对象,而是 react包装过的对象,  原生事件对象被放在了属性e.nativeEvent) ![](https://img.kancloud.cn/2a/e6/2ae65d906ca0083a630bf688bff117f0_1380x248.png) 2. 对原生事件的升级和改造 当我们给input声明个onChange事件,可以看到react不只是注册了一个onchange事件,还注册了很多其他事件。 额外的增加一些其他的事件,帮助我们提升交互的体验。 3. 阻止冒泡:e.stopPropagation() 4. 阻止默认行为:e.preventDefault() 5. 合成事件系统只是 DOM 事件系统的一个子集 ![](https://img.kancloud.cn/70/42/7042f024ee8dfae862cfd47838558713_2057x1026.png) ### 在 react 中使用原生事件 ![](https://img.kancloud.cn/48/63/4863fdb827cae1452caf77d4961ce966_1396x321.png)