React中点击子元素触发父元素点击事件的问题
解决React中子元素点击触发父元素事件的问题
这是React开发里非常常见的事件冒泡问题——DOM事件默认会从触发元素向上传播到所有祖先元素,所以你点击子<li>时,父<li>的点击事件也会被触发。下面给你几种实用的解决办法:
方法1:阻止事件冒泡(最常用)
在子元素的点击事件中调用event.stopPropagation(),直接阻止事件向上传播到父元素的事件监听器:
<ul className="sb-modules-list"> <li key={index} className={this.getModuleClass(module)} onClick={() => { alert(127) }}> <ul className="sb-module-steps-list"> { module.steps && module.steps.map((stepInfo, stepIndex) => ( <li key={stepIndex} className={this.getStepClass(stepInfo)} onClick={(event) => { event.stopPropagation(); // 关键:阻止事件冒泡 alert(456); }} > <p>{stepInfo.short_title}</p> </li> ))} </ul> </li> </ul>
这样点击子<li>时,只会执行自己的alert(456),父元素的alert(127)不会被触发。
方法2:区分触发事件的元素
如果不想阻止事件冒泡(比如父元素还有其他需要依赖冒泡的逻辑),可以在父元素的点击事件里,通过event.currentTarget和event.target判断实际触发事件的元素是不是父元素本身:
<ul className="sb-modules-list"> <li key={index} className={this.getModuleClass(module)} onClick={(event) => { // 只有点击父li本身时才执行逻辑 if (event.currentTarget === event.target) { alert(127); } }} > <ul className="sb-module-steps-list"> { module.steps && module.steps.map((stepInfo, stepIndex) => ( <li key={stepIndex} className={this.getStepClass(stepInfo)} onClick={() => { alert(456) }} > <p>{stepInfo.short_title}</p> </li> ))} </ul> </li> </ul>
event.currentTarget:绑定事件的元素(这里是父<li>)event.target:实际被点击的元素(子<li>或<p>)
当点击子元素时,target不等于currentTarget,父元素的逻辑就不会执行。
方法3:使用捕获阶段事件(较少用)
还可以给父元素使用onClickCapture(在事件捕获阶段触发),然后结合条件判断,但这种方式不如前两种直观,一般只在特殊场景下使用:
<ul className="sb-modules-list"> <li key={index} className={this.getModuleClass(module)} onClickCapture={(event) => { // 判断实际点击元素是否属于父li的直接子元素外的部分 if (!event.target.closest('.sb-module-steps-list')) { alert(127); } }} > <ul className="sb-module-steps-list"> { module.steps && module.steps.map((stepInfo, stepIndex) => ( <li key={stepIndex} className={this.getStepClass(stepInfo)} onClick={() => { alert(456) }} > <p>{stepInfo.short_title}</p> </li> ))} </ul> </li> </ul>
总结
如果没有特殊需求,方法1是最简单直接的解决方案;如果需要保留事件冒泡的其他作用,可以选择方法2。
内容的提问来源于stack exchange,提问作者prajeesh
相关产品推荐
相关产品推荐

