赞
踩
其他前端有趣的例子和坑合集:https://github.com/wqhui/blog
代码链接:https://codepen.io/Lik_Lit/pen/OJLROMW
做开发中,React 和 JS 原生事件监听addEventListener
混用了,因此发现了一个现象:React的阻止冒泡并没有阻止原生JS监听的事件触发。
例子中:onClik
阻止冒泡事件并没有生效,仅仅只是阻止outClick
,我的需求是只触发inner dom click
。
例子中有4个click
监听:
innerClick
,也是点击事件的触发者outClick
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.nativeEvent.stopImmediatePropagation
可以阻止冒泡到原生事件,我就在在innerClick
事件里加上了这句,输出变成了
“root click”
“inner dom click”
可以看到还是不行,因为stopImmediatePropagation
只是阻止同层级且绑定靠后的事件(具体参考MDN),这里只阻止了document
层的事件,同时也验证了上面说的本质上所有的事件绑定是代理到document上的的说法。
那非document
层的原生事件我们要怎么阻止呢?我这边只能想到笨方法:React要阻止冒泡到原生事件只有使用原生的绑定去调用e.stopPropagation()
refCb = (dom) => {
//这里我就没有去解绑了
dom && dom.addEventListener('click',this.innerClick)
}
<button ref={this.refCb} > 测试冒泡</button>
这样就可以解决了
JSX
写法绑定的事件都是合成事件,它们本质上是代理到document的事件,这就相当于事件委托,当某个事件触发时,该事件会冒泡到document
上面,React监听到这次事件开始统一分发合成事件给监听的回调函数处理(可以理解成React所有事件都是绑定在document
层,React V17之后是绑定到root
节点层)e.stopPropagation()
只能阻止React合成事件的冒泡,e.nativeEvent.stopImmediatePropagation
只能用来阻止冒泡到直接绑定在document上的事件JSX
写法绑定的事件和addEventListener
事件,要想阻止底层事件冒泡到二者,只有通过原生事件对象e.stopPropagation()
去阻止冒泡Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。