2017-04-05 36 views
1

所以,我有一個自定義的搜索和選擇組件,使輸入和包裹在一個父容器結果列表:如何隱藏輸入或孩子未使用React聚焦的div?

<div className='wrapper'> 
    <input /> 
    <div className='results'> 
    <div>Result Item</div> 
    <div>Result Item</div> 
    <div>Result Item</div> 
    <div>Result Item</div> 
    <div>Result Item</div> 
    </div> 
</div> 

我想要實現的是,當用戶集中在input的出現結果列表div。我使用一段狀態來實現這一點 - isExpanded。所以,我用的是輸入的聚焦狀態的方法:

<input onFocus={this.handleFocus} /> 

而且功能:

handleFocus =() => { 
    this.setState({ 
    isExpanded: true 
    }); 
} 

那偉大工程。我遇到的問題是在適當的時候關閉它。只有當用戶在wrapperdiv以外的物理點擊時它才應該關閉。當我需要它保持開放:

  • 如果用戶點擊任何結果的項目
  • 如果用戶集中於輸入,然後點擊結果項目
  • 如果用戶點擊結果項目,然後集中在輸入

因此,基本上wrapper div內的任何交互應保持打開狀態。

爲了試圖做到這一點,我已經把一個模糊事件周圍的包裝:

<div className='wrapper' tabIndex='1' onBlur={this.handleBlur}> ... </div> 

然後是功能

handleBlur =() => { 
    this.setState({ 
    isExpanded: false 
    }); 
} 

的問題是,當單擊一個項目或專注於輸入會消除事件觸發的焦點wrapper,因爲它應該這樣做,但是當我不希望它發生時我無法阻止它發射。

我使用document.activeElement混合ReactDOM.findDOMNode到有源元件比較試過了,但它仍然沒有工作。有任何想法嗎?

這裏是我想要達到一個基本的例子(它使用不同的功能結合的方法,但問題依然存在):

class SearchAndSelect extends React.Component { 
 

 
    constructor() { 
 
    super(); 
 
    this.state = { 
 
    \t isExpanded: false 
 
    } 
 
    this.handleBlur = this.handleBlur.bind(this); 
 
    this.handleFocus = this.handleFocus.bind(this); 
 
    } 
 
    
 
    handleBlur() { 
 
    this.setState({ 
 
     isExpanded: false 
 
    }) 
 
    } 
 
    
 
    handleFocus() { 
 
    this.setState({ 
 
     isExpanded: true 
 
    }) 
 
    } 
 
    
 
    render(){ 
 
    return(
 
     <div className='wrapper' tabIndex='1' onBlur={this.handleBlur}> 
 
     <input onFocus={this.handleFocus} /> 
 
     {this.state.isExpanded && <div>Results</div>} 
 
     </div> 
 
    ); 
 
    } 
 

 
} 
 

 
ReactDOM.render(<SearchAndSelect />, document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> 
 
<div id="container"></div>

回答

1

你可以說你要模糊被忽略,如果鼠標是你的包裝內上下時,模糊事件發生。我已經使用this.ignoreBlur來指示是否應該忽略模糊 - 我沒有使用狀態,因爲你不想要或需要這樣做導致重新渲染。我還包括移出包裝重置ignoreBlur萬一鼠標停下來,你永遠不會得到包裝的鼠標事件,這將使ignoreBlur永久爲真!

<div className='wrapper' onMouseDown={this.setIgnoreBlur} onMouseUp={this.clearIgnoreBlur} onMouseOut={this.clearIgnoreBlur} onBlur={this.handleBlur}> 
    <input /> 
    <div className='results'> 
    <div>Result Item</div> 
    <div>Result Item</div> 
    <div>Result Item</div> 
    <div>Result Item</div> 
    <div>Result Item</div> 
    </div> 
</div> 

setIgnoreBlur =() => { 
    this.ignoreBlur = true; 
} 

clearIgnoreBlur =() => { 
    this.ignoreBlur = false; 
} 

handleBlur =() => { 
    if (this.ignoreBlur) return; 
    this.setState({ 
    isExpanded: false 
    }); 
} 

我更新了你的提琴:https://jsfiddle.net/jwm6k66c/2474/

0

我已經做了一些

<div className='closer' onClick={this.handleBlur... 
<div className='wrapper'... 

.closer: 
position: absolute 
width/height:100% 
0

這高階組件可以幫助你:相似的,我通過具有下一個div實現它https://github.com/kentor/react-click-outside

參見那裏的例子。您需要使用它來增強您的包裝組件,然後將this.setState({ isExpanded: false })納入handleClickOutside()方法。