Event Handler ----React事件
React中的事件包括合成事件和原生事件,React底层对合成事件进行事件委派和手动绑定,原生事件的使用在高程3有具体讲解,难点在于跨浏览器兼容和DOM0/DOM2级事件处理程序的使用方法不同,这可以通过编写工具函数屏蔽浏览器差异,关于原生事件的描述在《Event Handler 事件处理程序 1》和《Event Handler 事件处理程序 2》中有详细解释。
合成事件:事件委派
React不会把事件处理函数直接绑定到真实的节点上,而是把所有事件绑定到最外层,使用一个统一的事件监听器,这个事件监听器上维持了一个映射来保存所有组件内部的事件监听和函数。当组件挂载或者卸载时,只是在这个统一的事件监听器上插入或者删除一些对象;当事件发生时,首先被这个统一的事件监听器处理,然后在映射里找到真正的事件处理函数并调用。这简化了事件处理和回收机制,效率也有很大提升。
合成事件:手动绑定
使用class或者纯函数创建组件时,this不会自动绑定,需要手动绑定:
1)bind方法,可以传递参数;
//在button上绑定事件处理函数,类似于DOM0级事件绑定
return <button onClick = {this.handleClick.bind(this,’test’)}> Test </button>
2)在class的构造函数constructor内部完成this绑定,仅需要一次绑定;
this.handleClick = this.handleClick.bind(this);
这是我目前常用的方法,一般在super(props)后面。
3)在组件内部创建时间通过箭头函数创建事件处理程序以实现绑定,由于箭头函数自动绑定了定义此函数作用域的this,不需要再使用bind方法。
class App extends Component{
const handle(e) = (e) =>{console.log(e);};
render(){
return <button onClick = {this.handleClick}> Test </button>;
}
}
在React中使用原生事件
在React中使用原生事件DOM2级事件:addEventListener()和removeEventListener()。为什么使用原生事件?因为有些时候需要将事件绑定在组件的父级元素上。在React中一般在componentDidMount之后调用原生事件,这时DOM节点已经确定。一定要在组件卸载时(componentWillUnmount)手动解除绑定,不然内存就会泄露。合成事件系统不需要这样,React已经妥善处理了这一点(怎么处理的?)。
对比React事件和JavaScript原生事件(DOM2级事件)
JavaScript原生事件传播有事件捕获、事件冒泡两个先后的过程,分别是由外到内和由内到外,事件捕获并不是一个通用的技术,在低于IE9版本的浏览器中无法使用。而且IE浏览器的事件处理机制和其他浏览器不同,通过原生JavaScript实现的通用事件处理程序中一般使用if else语句对浏览器差异性进行屏蔽。React的合成事件实现中,仅仅对最外层容器进行绑定,并且依赖事件冒泡完成事件委派,避免了事件捕获的浏览器不兼容特性。
最好避免同时使用原生事件和合成事件,混用时由于合成事件机制将事件绑定在了最外层,对内层组件上的事件处理函数使用e.preventDefault()无法阻止事件默认操作,因为事件不知道自身绑定在内部组件上。最好的方法是不混用合成事件和原生事件,或者混用时通过在if语句中使用e.target判断事件的直接绑定元素是不是内部组件。