javascript - 管理 React 中的焦点

标签 javascript reactjs

我正在使用 React 编写自动完成功能,当用户选择列表中的某个项目时,我希望更新输入。我的问题是,当输入失去焦点时,我希望菜单消失,除非用户在菜单中选择。目前,显示菜单基于名为 showDropDown 的属性。在渲染方法中,我有 if showDropDown 它构建菜单组件。似乎 render 方法是在菜单项上的单击监听器之前调用的,并且在调用 onClick 之前删除它们。

handleOnBlur = () => {
  this.setState({ showDropDown: false });
};

handleOnFocus = () => {
  this.setState({ showDropDown: true });
};
handleRenderSubComponents = (options) => {
  ...
  return options.map((option) => {
    ...
    return (<li key={displayString} className={className}>
      <span onClick={() => {this.handleOnItemSelect(option, fieldInput);}} style={{ cursor: 'pointer' }}>
        {displayString}
      </span>
    </li>);
  });
};
render() {
 ...
  return (
    <div className={className}>
      <div>
        <input
          style={{ position: 'relative' }}
          disabled={disabled}
          ref={(inputElem) => {this.inputElem = inputElem;}}
          valueLink={{ value: this.state.value, requestChange: (value) => this.handleOnChange(value) }}
          onBlur={this.handleOnBlur}
          onFocus={this.handleOnFocus}
          onKeyUp={this.handleOnKeyUp}
        />
      </div>
      <ul className="dropdown-menu dropdown-menu-justify" style={dropDownStyle} >
        {showDropDown && this.handleRenderSubComponents(options)}
      </ul>
    </div>
  );
}

我需要做的只是在输入失去焦点时隐藏菜单,但焦点不在菜单中

最佳答案

我认为这可以满足您的需要。关键是容器上的 onMouseDown 事件在输入上的 onBlur 之前触发。因此,我们设置了一个可以在 onBlur 中检查的类变量,如果单击了容器,我们将强制焦点返回到输入。 setTimeout 再次清除该变量,因此执行顺序将是 onMouseDown、onBlur、setTimeout 回调。

jsfiddle

 class App extends React.Component {
    constructor(props) {
    super(props);
    this.onInputChange = this.onInputChange.bind(this);
    this.onInputBlur = this.onInputBlur.bind(this);
    this.onContainerMouseDown = this.onContainerMouseDown.bind(this);
    this.onOptionClick = this.onOptionClick.bind(this);

    this.state = {
      input: '',
      showList: false
    };

    this.options = ['Option 1', 'Option 2', 'Option 3', 'Option 4'];
  }
  componentWillUnmount() {
    clearTimeout(this.containerMouseDownTimeout);
  }
  onInputChange(e) {
    this.setState({input: e.target.value, showList: e.target.value.length > 2});
  }
  onInputBlur() {
    const showList = this.clickedInContainer && this.state.input.length > 2;

    this.setState({
      showList
    });

    if (showList) {
      this.input.getDOMNode().focus();
    }
  }
  onContainerMouseDown() {
    this.clickedInContainer = true;

    this.containerMouseDownTimeout = setTimeout(() => {
        this.clickedInContainer = false;
    });
  }
  onOptionClick(option) {
    this.setState({
        input: option,
      showList: false
    })
  }
  renderList() {
    return (
      <ol style={{cursor: 'pointer'}}>
                {this.options.map((o, i) => <li key={i} onClick={() => this.onOptionClick(o)}>{o}</li>)}
      </ol>);
  }
  render() {
    return (
        <div onMouseDown={this.onContainerMouseDown}>
          <input ref={ref => this.input = ref} value={this.state.input} 
            onChange={this.onInputChange} onBlur={this.onInputBlur}/>
          {this.state.showList && this.renderList()}
      </div>
    )
  }
}

React.render(<App />, document.getElementById('container'));

关于javascript - 管理 React 中的焦点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38628211/

相关文章:

reactjs - getStaticPaths Next JS 中未定义的路径

javascript - Dialog Material-UI 从底部开始滚动

javascript - 原型(prototype)继承理解

javascript - 访问 Javascript promise 链中的变量

javascript - 如何在使用 Grails 3.3.2 的 war 版本中不生成 .gz 文件

javascript - jQuery 验证不适用于 Web 表单

javascript - 我可以使用 JavaScript 强制刷新 iframe 吗?

reactjs - npm 错误! 401 Unauthorized : @babel/core@7. 1.0 使用创建新的 React 应用程序时

reactjs - 如何使用 react-google-recaptcha-v3 验证 token 并获得分数?

通过 Ruby Gem Devise 进行 JavaScript React 身份验证?