React - 带有 onBlur 事件的 ul 阻止 onClick 在 li 上触发
Posted
技术标签:
【中文标题】React - 带有 onBlur 事件的 ul 阻止 onClick 在 li 上触发【英文标题】:React - ul with onBlur event is preventing onClick from firing on li 【发布时间】:2017-10-23 20:20:00 【问题描述】:我创建了一个移动下拉菜单,可以根据状态切换打开和关闭。打开后,我希望用户能够通过单击 ul 之外的任何位置来关闭下拉菜单。
我将 ul 上的 tabIndex 属性设置为 0,这使 ul 成为“焦点”。我还向 ul 添加了一个 onBlur 事件,该事件触发隐藏 ul 的状态更改 (dropdownExpanded = false)。
<ul tabIndex="0" onBlur=this.hideDropdownMenu>
<li onClick=this.handlePageNavigation>Page 1</li>
<li onClick=this.handlePageNavigation>Page 2</li>
<li onClick=this.handlePageNavigation>Page 3</li>
</ul>
但是,当我实施此修复时,我在每个 li 元素上的 onClick 事件都无法触发。
我知道事件冒泡发生了一些事情,但我不知道如何解决它。有人可以帮忙吗?
注意:
我知道您可以在 ul 下方创建一个跨越整个视口的透明 div,然后只需向该 div 添加一个 onClick 即可更改状态,但我阅读了有关此 tabIndex/focus 解决方案 on Stack Overflow 和我我真的很想让它工作。
这里是更完整的代码视图(下拉列表供用户选择他们的国家,这会更新 ui):
const mapStateToProps = (state) =>
return
lang: state.lang
const mapDispatchToProps = (dispatch) =>
return actions: bindActionCreators( changeLang , dispatch) ;
class Header extends Component
constructor()
super();
this.state =
langListExpanded: false
this.handleLangChange = this.handleLangChange.bind(this);
this.toggleLangMenu = this.toggleLangMenu.bind(this);
this.hideLangMenu = this.hideLangMenu.bind(this);
toggleLangMenu ()
this.setState(
langListExpanded: !this.state.langListExpanded
);
hideLangMenu ()
this.setState(
langListExpanded: false
);
handleLangChange(e)
let newLang = e.target.attributes['0'].value;
let urlSegment = window.location.pathname.substr(7);
// blast it to shared state
this.props.actions.changeLang( newLang );
// update browser route to change locale, but stay where they are at
browserHistory.push(`/$ newLang /$ urlSegment `);
//close dropdown menu
this.hideLangMenu();
compileAvailableLocales()
let locales = availableLangs;
let selectedLang = this.props.lang;
let markup = _.map(locales, (loc) =>
let readableName = language[ selectedLang ].navigation.locales[ loc ];
return (
<li
key= loc
value= loc
onMouseDown= this.handleLangChange >
readableName
</li>
);
);
return markup;
render()
let localeMarkup = this.compileAvailableLocales();
return (
<section className="header row expanded">
< Navigation />
<section className="locale_selection">
<button
className="btn-locale"
onClick=this.toggleLangMenu>
this.props.lang
</button>
<ul
className=this.state.langListExpanded ? "mobile_open" : " "
value= this.props.lang
tabIndex="0"
onBlur=this.hideLangMenu>
>
localeMarkup
</ul>
</section>
</section>
)
【问题讨论】:
【参考方案1】:我刚刚遇到了一系列面包屑链接,其中一个 onBlur 处理程序导致重新呈现,从而阻止链接点击工作。实际问题是 react 每次都在重新生成链接元素,所以当它重新渲染时,它会将链接从鼠标下方换出,导致浏览器忽略点击。
解决方法是在我的链接中添加 key
属性,以便 react 重用相同的 DOM 元素。
<ol>
props.breadcrumbs.map(crumb => (
<li key=crumb.url>
<Link to=crumb.url >
crumb.label
</Link>
</li>
))
</ol>
【讨论】:
【参考方案2】:关键是 onBlur 正在触发重新渲染,这似乎导致浏览器不跟进 onClick:https://github.com/facebook/react/issues/4210
但是,如果您检查 onBlur 事件,您可以找到一些关于正在发生的事情的信息,event.relatedTarget 已填充,您可以使用这些信息来检测 onBlur 何时实际由 onClick 触发并链接您需要执行的任何操作。
【讨论】:
使用 event.relatedTarget 对于不需要 onClick 处理程序的交互式元素(例如链接)特别有用。 嘿,你能看看这个吗? ***.com/questions/63686646/…event.relatedTarget
onBlur 事件仅在新事物获得关注时才会填充。这要求列表元素是可聚焦的,这可能合适也可能不合适。 developer.mozilla.org/en-US/docs/Web/API/FocusEvent/…【参考方案3】:
尝试使用 onMouseDown 而不是 onClick。
【讨论】:
谢谢,斯蒂芬。我试过了。这确实使 li 上的事件着火了。但是现在当你点击离开 ul 时,onBlur 事件不会触发。 你能再展示一些你的代码吗?我在this jsfiddle 中对其进行了测试,虽然没有显示和隐藏菜单的代码,但似乎添加 onMouseDown 处理程序不会直接干扰 onBlur 处理程序。 感谢您的链接,斯蒂芬。我已经为整个组件添加了代码。 您的下拉菜单可能永远不会获得焦点,因此永远不会失去焦点,这会触发回调。我相信this fiddle 会做你想做的事。重要的变化在第 18 行和第 67 行。 是的!这似乎是正在发生的事情。你的解决方案奏效了。再次感谢斯蒂芬!以上是关于React - 带有 onBlur 事件的 ul 阻止 onClick 在 li 上触发的主要内容,如果未能解决你的问题,请参考以下文章
react js中的window.onblur事件没有在android webview中被调用
JS事件 失焦事件(onblur)onblur事件与onfocus是相对事件,当光标离开当前获得聚焦对象的时候,触发onblur事件,同时执行被调用的程序。