react事件是合成事件,即最终会将事件代理到documet
对象上,为了提高性能。
一个典型的场景是页面弹出对话框,点击页面其他位置需要隐藏该对话框,点击对话框本身不隐藏。
一般会在document
上addEventListener
,在触发对象事件中使用stopPropagation
如果你这么做,很遗憾会得到错误的结果
下面是一个使用事件冒泡模型的处理方式
将事件添加到document
对象,未达预期
export default () => {
const clickListener = e => {
console.log("clickListener")
}
useEffect(() => {
//使用事件冒泡模型
document.addEventListener("click", clickListener, false)
return () => document.removeEventListener("click", clickListener, false)
}, [])
const handleClick = e => {
e.stopPropagation()
console.log("click")
}
return (
<>
<button onClick={e => handleClick(e)}>test click</button>
</>
)
}
将事件添加到window对象上,达到预期
export default () => {
const clickListener = e => {
console.log("clickListener")
}
useEffect(() => {
//使用事件冒泡模型
window.addEventListener("click", clickListener, false)
return () => window.removeEventListener("click", clickListener, false)
}, [])
const handleClick = e => {
e.stopPropagation()
console.log("click")
}
return (
<>
<button onClick={e => handleClick(e)}>test click</button>
</>
)
}
解释一下
因为使用事件冒泡模型,最终事件会冒泡到window
对象上,我们在window
对象上添加事件监听,button
的click
事件会代理到document
上执行,因为添加了stopPropagation
,因此不会再向上冒泡到window
了,也就不会触发window
的的click
事件
如果非要将事件添加到document上如何破?
使用stopImmediatePropagation
,阻止原生事件与document间的冒泡
export default () => {
const clickListener = e => {
console.log("clickListener")
}
useEffect(() => {
document.addEventListener("click", clickListener, false)
return () => document.removeEventListener("click", clickListener, false)
}, [])
const handleClick = e => {
// e.stopPropagation()
e.nativeEvent.stopImmediatePropagation()
console.log("click")
}
return (
<>
<button onClick={e => handleClick(e)}>test click</button>
</>
)
}
网友评论