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

时间:2017-05-23 18:19:04

标签: javascript html 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>

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

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

注:

我知道你可以创建一个跨越整个视口的ul下方的透明div,然后只添加一个onClick甚至可以改变状态的div,但我读到了这个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>
        )
    }
}

3 个答案:

答案 0 :(得分:9)

尝试使用onMouseDown而不是onClick。

答案 1 :(得分:0)

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

但是,如果您检查onBlur事件,则可以找到有关正在发生的事情的一些信息,event.relatedTarget会被填充,您可以使用这些信息来检测onBlur何时真正由onClick触发并进行链结。 / p>

答案 2 :(得分:0)

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

解决方法是将key属性添加到我的链接中,以便react可以重用相同的DOM元素。

<ol>
    {props.breadcrumbs.map(crumb => (
        <li key={crumb.url}>
            <Link to={crumb.url} >
                {crumb.label}
            </Link>
        </li>
    ))}
</ol>