We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
做开发中,React 和 JS 原生事件监听addEventListener混用了,因此发现了一个现象:React的阻止冒泡并没有阻止原生JS监听的事件触发。 例子中:onClik阻止冒泡事件并没有生效,仅仅只是阻止outClick,我的需求是只触发inner dom click。
addEventListener
onClik
outClick
inner dom click
代码链接:https://codepen.io/Lik_Lit/pen/OJLROMW
例子中有4个click监听:
click
innerClick
root click
document
document click
const domContainer = document.querySelector('#root') // 绑定在外层的点击 非documemt层的原生事件 domContainer.addEventListener('click', e => console.log('root click')) class InnerDom extends React.Component { componentDidMount () { // documemt层的原生事件 document.addEventListener('click', () => { console.log('document click') }) } outClick = (e) => { console.log('out dom click') } innerClick = (e) => { e.stopPropagation(); console.log('inner dom click') } render () { return <div onClick={this.outClick}> <button onClick={this.innerClick}> 测试冒泡</button> </div> } } ReactDOM.render(<InnerDom />, domContainer)
猜猜输出是什么?
"root click" "inner dom click" "document click"
原来 React 的组件不是挂载到对应元素上的,而且被统一管理起来的合成事件,本质上所有的事件绑定是代理到document上的,然后再触发的时候再根据不同元素去分发执行。类似下面:
// react所有合成事件, SyntheticEvent里面执行回调函数 document.addEventListener('click', SyntheticEvent); // 浏览器原生 document.addEventListener('click', () => { alert('document click'); })
所以在 React 绑定的合成事件调用e.stopPropagation()阻止的只是React的合成事件(eg:<div onClick={()=>{}}/>),而对于原生事件还是阻止不了
e.stopPropagation()
<div onClick={()=>{}}/>
百度告诉我说e.nativeEvent.stopImmediatePropagation可以阻止冒泡到原生事件,我就在在innerClick事件里加上了这句,输出变成了
e.nativeEvent.stopImmediatePropagation
"root click" "inner dom click"
可以看到还是不行,因为stopImmediatePropagation只是阻止同层级且绑定靠后的事件(具体参考MDN),这里只阻止了document层的事件,同时也验证了上面说的本质上所有的事件绑定是代理到document上的的说法。
stopImmediatePropagation
那非document层的原生事件我们要怎么阻止呢?我这边只能想到笨方法:React要阻止冒泡到原生事件只有使用原生的绑定去调用e.stopPropagation()
refCb = (dom) => { //这里我就没有去解绑了 dom && dom.addEventListener('click',this.innerClick) } <button ref={this.refCb} > 测试冒泡</button>
这样就可以解决了
JSX
root
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
做开发中,React 和 JS 原生事件监听
addEventListener
混用了,因此发现了一个现象:React的阻止冒泡并没有阻止原生JS监听的事件触发。例子中:
onClik
阻止冒泡事件并没有生效,仅仅只是阻止outClick
,我的需求是只触发inner dom click
。例子中有4个
click
监听:innerClick
,也是点击事件的触发者outClick
root click
,注意是原生的监听document
的监听document click
,注意是原生的监听猜猜输出是什么?
解决过程与坑
原来 React 的组件不是挂载到对应元素上的,而且被统一管理起来的合成事件,本质上所有的事件绑定是代理到
document
上的,然后再触发的时候再根据不同元素去分发执行。类似下面:所以在 React 绑定的合成事件调用
e.stopPropagation()
阻止的只是React的合成事件(eg:<div onClick={()=>{}}/>
),而对于原生事件还是阻止不了百度告诉我说
e.nativeEvent.stopImmediatePropagation
可以阻止冒泡到原生事件,我就在在innerClick
事件里加上了这句,输出变成了可以看到还是不行,因为
stopImmediatePropagation
只是阻止同层级且绑定靠后的事件(具体参考MDN),这里只阻止了document
层的事件,同时也验证了上面说的本质上所有的事件绑定是代理到document上的的说法。那非
document
层的原生事件我们要怎么阻止呢?我这边只能想到笨方法:React要阻止冒泡到原生事件只有使用原生的绑定去调用e.stopPropagation()
这样就可以解决了
结论
JSX
写法绑定的事件都是合成事件,它们本质上是代理到document的事件,这就相当于事件委托,当某个事件触发时,该事件会冒泡到document
上面,React监听到这次事件开始统一分发合成事件给监听的回调函数处理(可以理解成React所有事件都是绑定在document
层,React V17之后是绑定到root
节点层)e.stopPropagation()
只能阻止React合成事件的冒泡,e.nativeEvent.stopImmediatePropagation
只能用来阻止冒泡到直接绑定在document上的事件JSX
写法绑定的事件和addEventListener
事件,要想阻止底层事件冒泡到二者,只有通过原生事件对象e.stopPropagation()
去阻止冒泡The text was updated successfully, but these errors were encountered: