Javascript React-ul with onBlur事件阻止onClick在li上触发

Javascript React-ul with onBlur事件阻止onClick在li上触发,javascript,html,css,reactjs,Javascript,Html,Css,Reactjs,我创建了一个移动下拉菜单,可以根据状态切换打开和关闭。一旦它被打开,我希望用户能够通过点击ul之外的任何地方来关闭下拉列表 我将ul上的tabIndex属性设置为0,这将提供ul“焦点”。我还向ul添加了一个onBlur事件,该事件触发隐藏ul的状态更改(dropdownExpanded=false) <ul tabIndex="0" onBlur={this.hideDropdownMenu}> <li onClick={this.handlePageNavigation

我创建了一个移动下拉菜单,可以根据状态切换打开和关闭。一旦它被打开,我希望用户能够通过点击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>
  • 第1页
  • 第2页
  • 第3页
但是,当我实现这个修复程序时,我在每个li元素上的onClick事件无法触发

我知道这件事有点不对劲,但我不知道如何解决它。有人能帮忙吗

注:

我知道你可以在ul下创建一个透明的div,它跨越整个视口,然后只需在该div上添加一个onClick即可改变状态,但是我读到了关于这个tabIndex/focus解决方案的文章,我真的很想让它工作

下面是代码的更完整视图(下拉列表供用户选择他们的祖国,这将更新ui):

const-mapStateToProps=(state)=>{
返回{
朗:state.lang
}
}
const mapDispatchToProps=(调度)=>{
返回{actions:bindActionCreators({changeLang},dispatch)};
}
类头扩展组件{
构造函数(){
超级();
此.state={
langListExpanded:false
}
this.handleLangChange=this.handleLangChange.bind(this);
this.toggleLangMenu=this.toggleLangMenu.bind(this);
this.hidelagmens=this.hidelagmens.bind(this);
}
切换菜单(){
这是我的国家({
langListExpanded:!this.state.langListExpanded
});
}
HidelangMenus(){
这是我的国家({
langListExpanded:false
});
}
handleLangChange(e){
让newLang=e.target.attributes['0'].value;
设URLSEMENT=window.location.pathname.substr(7);
//把它炸成共享状态
this.props.actions.changeLang(newLang);
//更新浏览器路径以更改区域设置,但保持其所在位置
push(`/${newLang}/${urlsem分段}`);
//关闭下拉菜单
this.hideLangMenu();
}
compileAvailableLocales(){
让locales=availableLangs;
让selectedLang=this.props.lang;
let markup=\ map(locales,(loc)=>{
让readableName=language[selectedLang].navigation.locales[loc];
返回(
  • {readableName}
  • ); }); 返回标记; } render(){ 让localeMarkup=this.compileAvailableLocales(); 返回( {this.props.lang}
      > {localeMarkup}
    ) } }
    尝试使用onMouseDown而不是onClick。

    关键是onBlur正在触发重新渲染,这似乎会导致浏览器不执行onClick:


    但是如果你检查onBlur事件,你可以找到一些关于正在发生什么的信息,event.relatedTarget会被填充,你可以使用这些信息来检测onBlur是何时被onClick和chain触发的,无论你需要做什么。

    我刚刚遇到了一系列面包屑链接,onBlur处理程序导致重新加载,从而阻止链接单击工作。实际的问题是react每次都会重新生成链接元素,因此当它重新渲染时,它会从鼠标下调出链接,这会导致浏览器忽略单击

    修复方法是向我的链接添加
    key
    属性,以便react可以重用相同的DOM元素

    <ol>
        {props.breadcrumbs.map(crumb => (
            <li key={crumb.url}>
                <Link to={crumb.url} >
                    {crumb.label}
                </Link>
            </li>
        ))}
    </ol>
    
    
    {props.breadcrumbs.map(crumb=>(
    
  • {crump.label}
  • ))}
    谢谢,斯蒂芬。我试过了。这确实使李上的事件火上浇油。但是现在当你点击离开ul时onBlur事件不会触发。你能再显示一些你的代码吗?我在中进行了测试,虽然没有显示和隐藏菜单的代码,但似乎添加onMouseDown处理程序不会直接干扰onBlur处理程序。感谢您的链接,Stephen。我已经为整个组件添加了代码。您的下拉列表可能永远不会获得焦点,因此也不会丢失,这将触发回调。我相信你做了你想做的事。重要的变化在第18行和第67行。是的!事情似乎就是这样。你的解决方案奏效了。再次感谢你,斯蒂芬!使用event.relatedTarget对于不需要onClick处理程序的交互元素(如链接)特别有用。嘿,你能看看这个吗<代码>事件。onBlur事件上的relatedTarget仅在新内容得到关注时才会填充。这要求列表元素是可聚焦的,这可能合适也可能不合适。
    <ol>
        {props.breadcrumbs.map(crumb => (
            <li key={crumb.url}>
                <Link to={crumb.url} >
                    {crumb.label}
                </Link>
            </li>
        ))}
    </ol>