2016-07-28 4 views
1

Ich schreibe eine Autovervollständigungsfunktion mit React, und wenn der Benutzer ein Element in der Liste auswählt, möchte ich die Eingabe aktualisieren. Mein Problem ist, wenn der Eingang den Fokus verliert. Ich möchte, dass das Menü verschwindet, wenn der Benutzer das Menü nicht auswählt. Momentan basiert das Anzeigen des Menüs auf einer Eigenschaft namens showDropDown. In der Render-Methode habe ich, wenn ShowDropDown es baut die Menü-Komponenten. Es scheint, dass die Rendermethode vor den Klicklistenern auf den Menüelementen aufgerufen wird und sie entfernt, bevor onClick aufgerufen wird.Fokus in Reagieren verwalten

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> 
); 
} 

Was ich tun muß, ist nur Menü ausgeblendet, wenn der Eingang des Fokus verliert, aber der Fokus ist nicht im Menü

+0

Wo ist der Code, der auf dem 'showDropDown' Zustand abhängt? –

+0

Nicht sicher, wie das auf der Kopie verpasst wurde. Zurück in hinzugefügt – user1760412

Antwort

0

Ich denke, das tut, was Sie brauchen. Der Schlüssel ist, dass das onMouseDown-Ereignis für den Container vor der onBlur-Eingabe ausgelöst wird. Also setzen wir eine Klassenvariable, die in der onBlur überprüft werden kann und wenn der Container angeklickt wurde, zwingen wir den Fokus zurück zur Eingabe. Das setTimeout löscht diese Variable erneut, sodass die Ausführungsreihenfolge onMouseDown, onBlur, setTimeout callback lautet.

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'));