this
React
事件和原生事件有什么区别React
事件和原生事件的执行顺序,能够混用吗React
事件如何解决跨浏览器兼容下面是我阅读过源码后,将全部的执行流程总结出来的流程图,不会贴代码,若是你想阅读代码看看具体是如何实现的,能够根据流程图去源码里寻找。node
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]
。例如:react
{ onClick:{ nodeid1:()=>{...} nodeid2:()=>{...} }, onChange:{ nodeid3:()=>{...} nodeid4:()=>{...} } }
这里的事件执行利用了React
的批处理机制,在前一篇的【React深刻】setState执行机制中已经分析过,这里再也不多加分析。segmentfault
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
本身实现的冒泡机制。babel
EventPluginHub
的extractEvents
方法。EventPlugin
(用来处理不一样事件的工具方法)。EventPlugin
中根据不一样的事件类型,返回不一样的事件池。nodeid
(惟一标识key
)和事件类型从listenerBink
中取出回调函数将上面的四个流程串联起来。dom
经过事件触发过程的分析,dispatchEvent
调用了invokeGuardedCallback
方法。函数
function invokeGuardedCallback(name, func, a) { try { func(a); } catch (x) { if (caughtError === null) { caughtError = x; } } }
可见,回调函数是直接调用调用的,并无指定调用的组件,因此不进行手动绑定的状况下直接获取到的this
是undefined
。工具
这里可使用实验性的属性初始化语法 ,也就是直接在组件声明箭头函数。箭头函数不会建立本身的this
,它只会从本身的做用域链的上一层继承this
。所以这样咱们在React
事件中获取到的就是组件自己了。this
React
事件使用驼峰命名,而不是所有小写。JSX
, 你传递一个函数做为事件处理程序,而不是一个字符串。例如,HTML
:spa
<button onclick="activateLasers()"> Activate Lasers </button>
在 React
中略有不一样:
<button onClick={activateLasers}> Activate Lasers </button>
另外一个区别是,在 React 中你不能经过返回 false
来阻止默认行为。必须明确调用 preventDefault
。
由上面执行机制咱们能够得出:React
本身实现了一套事件机制,本身模拟了事件冒泡和捕获的过程,采用了事件代理,批量更新等方法,而且抹平了各个浏览器的兼容性问题。
React
事件和原生事件的执行顺序componentDidMount() { this.parent.addEventListener('click', (e) => { console.log('dom parent'); }) this.child.addEventListener('click', (e) => { console.log('dom child'); }) document.addEventListener('click', (e) => { console.log('document'); }) } childClick = (e) => { console.log('react child'); } parentClick = (e) => { console.log('react parent'); } render() { return ( <div onClick={this.parentClick} ref={ref => this.parent = ref}> <div onClick={this.childClick} ref={ref => this.child = ref}> test </div> </div>) }
执行结果:
由上面的流程咱们能够理解:
react
的全部事件都挂载在document
中document
后才会对react
事件进行处理react
合成事件document
上挂载的事件react
事件和原生事件最好不要混用。
原生事件中若是执行了stopPropagation
方法,则会致使其余react
事件失效。由于全部元素的事件将没法冒泡到document
上。
由上面的执行机制不可贵出,全部的react事件都将没法被注册。
function handleClick(e) { e.preventDefault(); console.log('The link was clicked.'); }
这里,e
是一个合成的事件。React
根据 W3C 规范 定义了这个合成事件,因此你不须要担忧跨浏览器的兼容性问题。
事件处理程序将传递 SyntheticEvent
的实例,这是一个跨浏览器原生事件包装器。 它具备与浏览器原生事件相同的接口,包括 stopPropagation()
和 preventDefault()
,在全部浏览器中他们工做方式都相同。
每一个 SyntheticEvent
对象都具备如下属性:
boolean bubbles boolean cancelable DOMEventTarget currentTarget boolean defaultPrevented number eventPhase boolean isTrusted DOMEvent nativeEvent void preventDefault() boolean isDefaultPrevented() void stopPropagation() boolean isPropagationStopped() DOMEventTarget target number timeStamp string type
React
合成的SyntheticEvent
采用了事件池,这样作能够大大节省内存,而不会频繁的建立和销毁事件对象。
另外,无论在什么浏览器环境下,浏览器会将该事件类型统一建立为合成事件,从而达到了浏览器兼容的目的。