React合成事件与原生事件的机制冲突

React合成事件与原生事件的机制冲突

场景,当在某组件/dom节点绑定事件时,如果此时document也绑定了事件,则会产生冒泡,触发document事件。

阻止冒泡:

原生场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<body>
<div id="div1" onclick="outclick()">
<div id="btn">click</div>
</div>
</body>

<script>
var outclick=function(){
console.log('div1 outclick')
}
var btnclick=function(e){
console.log('btn click')
e.stopPropagation();
}

document.getElementById('btn').addEventListener('click',btnclick)
document.addEventListener('click',function(){
console.log('document click')
})
</script>

原生场景下只需要对你想触发的元素监听并触发e.stopPropagation()即可组织冒泡;

react场景

首先我们看到如果在react中同样使用e.stopPropagation(),会有什么效果?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Home extends Component {
constructor () {
super()
}

componentDidMount () {
document.addEventListener('click', () => {
alert('document click')
})
document.getElementsByClassName('home-leftwrap')[0].addEventListener('click', () => {
alert('原生outClick')
})
}

outClick (e) {
console.log(e.currentTarget)
alert('合成outClick')
}

onClick (e) {
console.log(e.currentTarget)
alert('btn Click')
e.stopPropagation()
}

render () {
return <div className="btn-wrap" onClick={this.outClick}>
<button className="btn" onClick={this.onClick}>click</button>

</div>
}
}

结果是:’原生outClick’, ‘btn Click’,’document click’;
结论是:e.stopPropagation()只能组织合成事件的冒泡,不能阻止原生事件的冒泡,更不能阻止原生document事件。

这里先暂时提一下合成事件与原生事件

1
2
3
4
5
6
7
// react 合成事件, dispatchEvent里面执行回调函数
document.addEventListener('click', dispatchEvent);

// 浏览器原生
document.addEventListener('click', () => {
alert('document click');
})

通过dispatchEvent分发注册的函数是挂载在document上的===相当于一开始都注册在document上,然后通过docuement的dispatchEvent来进行分发。

怎么阻止document触发呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Home extends Component {
constructor () {
super()
}

componentDidMount () {
document.addEventListener('click', () => {
alert('document click')
})
document.getElementsByClassName('home-leftwrap')[0].addEventListener('click', () => {
alert('原生outClick')
})
}

outClick (e) {
console.log(e.currentTarget)
alert('合成outClick')
}

onClick (e) {
console.log(e.currentTarget)
alert('btn Click')
e.nativeEvent.stopImmediatePropagation()
e.stopPropagation()
}

render () {
return <div className="btn-wrap" onClick={this.outClick}>
<button className="btn" onClick={this.onClick}>click</button>
</div>
}
}

e.nativeEvent.stopImmediatePropagation(),dispatchEvent里的stopImmediatePropagation可以使得绑定在document上的其他事件不会被触发;值得注意的是,并不会阻止其他父级节点冒泡;如果想要阻止全部冒泡事件,还是通过ref获取节点并监听事件阻止。