# react合成事件
# 首先来复习一下JS原生DOM事件绑定的三种方式:
1】直接在标签属性绑定事件
- 需要在标签属性中立即执行绑定的函数
- 可以直接
return false;
进行阻止默认事件。 - 没有event对象
<div id="btn" onclick="clickone();return false;"></div> //直接在DOM里绑定事件,需要写成立即执行的格式
<script>
function clickone(){ alert("hello"); }
</script>
2】通过获取DOM绑定事件
- 在脚本中通过匿名函数的方式绑定的只会执行最后一个事件。
- 也可以使用
return false;
进行阻止默认事件。也可以使用e.preventDefault()
<div id="btn"></div>
<script>
document.getElementById("btn").onclick = function(e){
//e.preventDefault()
alert("hello");
return false
}
</script>
3】添加事件监听函数
- 用 "addEventListener" 可以绑定多次同一个事件,且都会执行,
- 而在DOM结构如果绑定两个 "onclick" 事件,只会执行第一个;
- 只能通过
e.preventDefault()
来阻止默认事件。
<div id="btn"></div>
<script>
document.getElementById("btn").addeventlistener("click",(e)=>{
e.preventDefault()//阻止默认事件
alert("hello")
},false);
</script>
# React合成事件理解:
参考资料:
react使用的是JSX语法,驼峰命名法,所以这里是事件onClick。
<div className="testDom" onClick={this.testDomClick}><div>
# React合成事件和原生事件区别:
React合成事件一套机制:React并不是将click事件直接绑定在dom上面,而是采用事件冒泡的形式冒泡到document上面,然后React将事件封装给SyntheticEvent函数处理、运行和处理。
如果DOM上绑定了过多的事件处理函数,整个页面响应以及内存占用可能都会受到影响。React为了避免DOM事件滥用,同时屏蔽底层不同浏览器之间的事件系统差异,实现了一个中间层——SyntheticEvent。
(类似于用中间层来事件委托)
- 冒泡到document顶层
- 当用户在为onClick添加函数时,React并没有将Click事件绑定在DOM上面。
- 封装所有事件给SyntheticEvent事件合成(负责所有事件合成)
- 而是在document处监听所有支持的事件,当事件发生并冒泡至document处时,React将事件内容封装交给中间层SyntheticEvent(负责所有事件合成)
- 函数dispatchEvent统一分发
- 所以当事件触发的时候,对使用统一的分发函数dispatchEvent将指定函数执行。
# React中使用原生事件:
由于原生事件需要绑定在真实DOM上,所以一般是在componentDidMount阶段
/ref的函数执行阶段
进行绑定操作,在componentWillUnmount阶段
进行解绑操作以避免内存泄漏。
示例如下:
class Demo extends React.PureComponent {
componentDidMount() {
const $this = ReactDOM.findDOMNode(this)
$this.addEventListener('click', this.onDOMClick, false)
}
onDOMClick = evt => {
// ...
}
render() {
return (
<div>Demo</div>
)
}
}
原生事件和react合成事件混合使用注意:
- 响应顺序(原生事件一般情况执行顺序先于react合成事件)
- 如果我们在原生事件中使用
e.stopPropagation()
进行阻止冒泡事件,可能会影响react合成事件的先外层冒泡,而导致错误
# 示例:
import React, { Component } from 'react'
export default class Event extends Component {
componentDidMount() {
const $this = this.refs.button
$this.addEventListener('click', this.onDOMClick, false)
}
onDOMClick = evt => {
console.log('dom event')
}
onClick = evt => {
console.log('react event')
}
render() {
return (
<div ref='button' onClick={this.onClick}>Demo</div>
)
}
}
执行结果:dom event react event(原生事件先于react合成事件执行)
如果我们现在将原生事件进行e.stopPropagation
阻止冒泡,则必将影响react合成事件不能顺利执行。(注意在react合成事件中是不能进行阻止冒泡操作的。)
import React, { Component } from 'react'
export default class Event extends Component {
componentDidMount() {
const $this = this.refs.button
$this.addEventListener('click', this.onDOMClick, false)
}
onDOMClick = evt => {
evt.stopPropagation()
console.log('dom event')
}
onClick = evt => {
console.log('react event')
}
render() {
return (
<div ref='button' onClick={this.onClick}>Demo</div>
)
}
}
此时只打印出:dom event,因为react合成事件的事件冒泡被影响了,没有顺利冒泡到document上面进行委托统一分发。