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

Jor*_*son 11 html javascript css reactjs

我创建了一个移动下拉菜单,根据状态切换打开和关闭.一旦打开,我希望用户能够通过点击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>
Run Code Online (Sandbox Code Playgroud)

但是,当我实现此修复程序时,我在每个li元素上的onClick事件都无法触发.

事件冒泡我知道事情正在发生,但我对如何修复它感到很失望.有人可以帮忙吗?

注意:

我知道你可以创建一个透明的div,它跨越整个视口的ul,然后只需添加一个onClick甚至可以改变状态的div,但我在Stack Overflow上读到了这个tabIndex/focus解决方案,我真的很喜欢让它工作.

这是一个更完整的代码视图(下拉列表是供用户选择他们的国家,更新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>
        )
    }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*n L 15

尝试使用onMouseDown而不是onClick.

  • 谢谢,斯蒂芬。我试过了。这确实让关于 li 的事件着火了。但是现在当您单击远离 ul 时 onBlur 事件不会触发。 (2认同)

Max*_*lli 9

关键是 onBlur 正在触发重新渲染,这似乎导致浏览器不跟进 onClick:https : //github.com/facebook/react/issues/4210

但是如果你检查 onBlur 事件,你可以找到一些关于正在发生的事情的信息, event.relatedTarget 被填充,你可以使用这些信息来检测 onBlur 何时实际被 onClick 触发并链接你需要做的任何事情。

  • 仅当有新内容获得焦点时,才会填充 onBlur 事件上的“event.latedTarget”。这要求列表元素是可聚焦的,这可能适合也可能不适合。https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/latedTarget (4认同)
  • 使用 event.latedTarget 对于不需要 onClick 处理程序(例如链接)的交互元素特别有用。 (2认同)