如何通过evt对象获取元素role属性 区分React点击事件触发源
解决父容器与内部子元素点击事件冲突的两种方案
你当前的实现仅在点击目标严格是按钮本身时生效,若按钮内部嵌套了图标、文字span等子元素,evt.target会指向子元素,导致判断失效,可参考以下两种成熟方案实现需求:
方案1:事件源向上匹配(推荐,无需阻止冒泡)
使用DOM的closest方法向上查询最近的符合特征的元素,兼容按钮内部嵌套子元素的场景,你可以用role属性,也可以用自定义data-*属性做标识,更符合语义规范:
const App = () => { const onClickDiv = (evt) => { // 向上查找最近的带有下拉按钮标识的元素,存在则说明点击了下拉按钮区域 if (evt.target.closest('[data-dropdown="button"]')) { console.warn('点击了下拉按钮,执行对应逻辑') } else { console.warn('点击了div非按钮区域,执行对应逻辑') } } const onClickDropdownButton = () => { console.log('执行下拉按钮自有逻辑') } return ( <div style={{ border: 'red solid 1px' }} onClick={onClickDiv}> 可点击的父div <div> {/* 用自定义data属性做标识,语义更清晰 */} <button onClick={onClickDropdownButton} data-dropdown="button"> {/* 就算嵌套子元素也不影响判断 */} <span>下拉按钮</span> </button> </div> </div> ) } ReactDOM.render( <App />, document.getElementById('app') );
div { padding: 10px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script> <div id="app"></div>
该方案适用场景:点击下拉按钮时,你需要同时触发按钮自有逻辑和父容器的分支逻辑。
方案2:子元素阻止事件冒泡
如果点击下拉按钮时完全不需要触发父div的点击逻辑,直接在按钮的点击事件里阻止事件向上冒泡即可,父容器不需要额外做判断:
const App = () => { const onClickDiv = (evt) => { console.warn('点击了div非按钮区域,执行对应逻辑') } const onClickDropdownButton = (evt) => { // 阻止事件冒泡到父div,父级点击事件不会触发 evt.stopPropagation() console.log('执行下拉按钮自有逻辑') } return ( <div style={{ border: 'red solid 1px' }} onClick={onClickDiv}> 可点击的父div <div> <button onClick={onClickDropdownButton}>下拉按钮</button> </div> </div> ) }
该方案适用场景:两种点击场景逻辑完全独立,不需要同时触发。
内容的提问来源于stack exchange,提问作者theJuls
相关产品推荐
相关产品推荐

