首先我们来看一段很简单的 react 代码
import React from 'react'
class EventDemo extends React.Component {
render() {
return <a href="https://baidu.com/" onClick={this.clickHandler}>
click me
</a>
}
// 获取 event
clickHandler = (event) => {
event.preventDefault()
console.log(event)
}
}
export default EventDemo
在函数没有传递参数的情况下,函数会自动获取一个 event 参数,这也是平时书写 JavaScript 事件时的默认参数。我们将 event 打印出来,看看是什么
同样的原生事件
感觉好像确实差不多。
再次打印当前点击所指的元素
console.log('target', event.target) // 指向当前元素,即当前元素触发
console.log('current target', event.currentTarget) // 指向当前元素,
但这一切都是假象!!!!
注意,event 其实是 React 封装的。可以看 __proto__.constructor
是 SyntheticEvent
组合事件。
不是原生的 Event ,原生的 MouseEvent。
console.log('event', event)
console.log('event.__proto__.constructor', event.__proto__.constructor)
原生 event 如下,其中 __proto__.constructor
是 MouseEvent
console.log('nativeEvent', event.nativeEvent)
console.log('nativeEvent target', event.nativeEvent.target) // 指向当前元素,即当前元素触发
console.log('nativeEvent current target', event.nativeEvent.currentTarget) // 指向 document !!!
综上:
event
是SyntheticEvent
,模拟出来 DOM 事件所有能力
event.nativeEvent
是原生事件对象
所有的事件,都被挂载到
document
上
和
DOM
事件不一样,和Vue
事件也不一样
事件响应
- React 在构建虚拟 DOM 的同时,还构建了自己的事件系统;所有事件对象和
W3C
规范保持一致 - React的事件系统和浏览器事件系统相比,主要增加了两个特性:事件代理,事件自动解绑
事件代理
- 区别于浏览器事件处理方式,React并未将事件处理函数与对应的 DOM 节点直接关联。而是在顶层使用一个全局事件监听器监听所有事件
- React 会在内部维护一个映射表记录事件与组件处理函数的对应关系
- 当某个事件触发时,React 根据这个内部映射表将事件分派给指定的事件处理函数
- 若映射表中没有事件处理函数时,React 不会做任何操作
- 当组件安装或卸载时,相应的事件处理函数会自动被添加到事件监听器的内部映射表中或从表中删除
事件自动绑定
- React 的每个事件处理回调函数都会自动绑定到组件实例(使用 ES6 语法创建的例外)。事件回调函数中的 this 指向的是组件实例而不是 DOM 元素
合成事件
- 是对浏览器原生事件的封装,与浏览器原生事件有同样的接口,如
stopPropagation(),preventDefault()
等,并且这些接口是跨浏览器兼容的。
React
并不是将事件绑在元素的真实 DOM
上,而是在 document
处监听所有支持的事件,当事件发生并冒泡至 document
处时,React将事件内容封装并交由真正的处理函数运行