事件系统
Virtual DOM在内存中是以对象的形式存在的,如果想要在这些对象上添加事件,就会非常简单。React基于Virtual DOM实现了一个合成事件层,它完全符合W3C标准,不会存在任何IE兼容问题,并且与原生的浏览器事件拥有同样的接口,同样支持事件的冒泡机制,我们可以使用stopPropagation()和preventDefault()来中断它
合成事件的绑定方式
React事件的绑定方式在写法上与原生的HTML事件监听器属性很相似,并且含义和触发的场景也全都是一致的,比如,以下的JSX代码表示为按钮添加点击事件:
<button onClick={this.handleClick}>Test</button>
//DOM0级的写法如下
<button onclick="handleClick()">Test</button>
我们会发现这种写法与DOM0级事件中直接设置HTML标签属性为事件处理器的做法有很大不同,首先它是一个函数引用,其次使用了驼峰的形式来书写事件的属性名
合成事件的实现机制
在React底层,主要对合成事件做了两件事:事件委派和自动绑定
- 事件委派
在使用React事件前,要熟悉它的事件代理机制,它并不会把事件处理函数直接绑定到真实的节点上,而是把所有事件绑定到结构的最外层,使用一个统一的事件监听器,当组件挂载或卸载时,只是在这个统一的实践监听器上插入或删除一些对象; 当事件发生时,首先被这个统一的事件监听器处理,然后在映射里找到真正的事件处理函数并调用
- 自动绑定
在React组件中,每个方法的上下文都会指向该组件的实例,即自动绑定this为当前组件,而且React还会对这种绑定进行缓存,以实现CPU和内存的最优化。但在使用ES6 classes或者纯函数时,这种自动绑定就不存在了,我们需要手动实现this的绑定。我们来看几种绑定的方法
- bind方法
这个方法可以帮助我们绑定事件处理器内的this,并可以向事件处理器中传递参数,如 :
import React, { Componet } from 'react';
class App extends Component {
handleClick(e, arg){
console.log(e, arg);
}
render(){
// 通过bind方法实现,可以传递参数
return <button onClick={this.handleClick.bind(this, 'test')}>Test</button>
}
}
如果方法只绑定,不传参,可以使用双冒号语法,Babel已经实现了该提案
return <button onClick={::this.handleClick}>Test</button>
- 构造器声明
这种绑定的好处在于只需要一次绑定
handleClick(e){
this.handleClick = this.handleClick.bind(this);
}
- 箭头函数
return <button onClick{()=>this.handleClick()} >Test</button>