[英]ReactJS Dropdown menu, close other menus before opening current
我做了一些下拉菜单:
export default class DropdownMenu extends Component {
constructor(props) {
super(props)
this.state = {
menuOpen: false,
highlight: false,
count: this.props.count | 0
}
this.showDropdown = this.showDropdown.bind(this);
}
componentDidMount() {
}
showDropdown() {
this.setState({
menuOpen: !this.state.menuOpen
});
}
render() {
return <div className="dropdown__menu" onClick={this.showDropdown}>
{this.props.text} {this.state.count > 0 ? <b>{this.state.count}</b> : ''}
<div className="dropdown__content" style={this.state.menuOpen ? {'display': 'block'} : {'display': 'none'}}>
{this.props.children}
</div>
</div>
}
}
问题是您可以打开所有它们并将它们保持打开状态,直到再次单击它们以将其关闭。 如何使打开的其他菜单在打开的同时关闭?
这是它们的实现位置:
render() {
...
<div className="filter_container">
<DropdownMenu text="New" count={127} disabled/>
<DropdownMenu text="Only show">
<li>New</li>
<li>Old</li>
</DropdownMenu>
<DropdownMenu text="Other">
<li>one</li>
<li>two</li>
</DropdownMenu>
<DropdownMenu text="Sort by">
<li>Name</li>
<li>Age</li>
<li>Value</li>
</DropdownMenu>
</div>
</div>
...
由于react有一种数据流方式,因此您需要在父组件中执行此操作
import React from 'react'
class DropdownParent extends React.Component {
state = {
openedDropdown: null,
};
render() {
return (
<React.Fragment>
<Dropdown
name="dropdown1"
isOpen={this.state.openedDropdown === 1}
onClick={() => this.setState({ openedDropdown: 1 })}
onClose={() => this.setState({ openedDropdown: null })}
/>
<Dropdown
name="dropdown2"
isOpen={this.state.openedDropdown === 2}
onClick={() => this.setState({ openedDropdown: 2 })}
onClose={() => this.setState({ openedDropdown: null })}
/>
</React.Fragment>
)
}
}
然后您需要Dropdown基于props.isOpen而不是基于state.menuOpen并使用props.onClick / props.onClose代替this.showDropdown
另外,您可以立足于鼠标(如onmousedown事件 OnMouseEnter在 ...)或聚焦( 聚焦状态 的onblur)事件,但是这是很难让移动友好的,并不会保证你关于“在同一时刻只有一个下拉菜单”。 更多信息: https : //reactjs.org/docs/events.html
您可以使用onBlur
因为当另一个被点赞时它会失去焦点。
class DropDown extends React.Component { state = { isVisible: false } closeMenu = () => { this.setState({ isVisible: false }) } toggleMenu = () => { this.setState(prevState => ({ isVisible: !prevState.isVisible })) } render() { const { isVisible } = this.state; return ( <div className="dropdown__menu" onBlur={this.closeMenu} tabIndex={0} role="menu" onClick={this.toggleMenu}> {isVisible ? 'visible' : 'hidden'} </div> ) } } const App = () => ( <div> <DropDown /> <DropDown /> </div> ) ReactDOM.render(<App />, document.getElementById('root'));
.dropdown__menu { outline: none; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <div id="root"></div>
由于打开不再是封装在下拉列表状态中的信息,因此建议将这些信息上移到父组件的状态。
现在,您应该将Dropdowns转换为无状态函数:
const DropdownMenu = ({ menuOpen, count, text, showDropdown }) => ( //props deconstruction
<div className="dropdown__menu" onClick={showDropdown}>
{text}
{count && <b>{count}</b>} //If you do not want to show anything if a condition is falsy, use the inline if &&
<div className="dropdown__content" style={{ 'display': menuOpen ? 'block' : 'none' }}> //You can put the ternary condition directly into the JSON
{this.props.children}
</div>
</div>
)
现在,您必须在父组件中存储打开了哪个dopdown:
class Parent extends Component {
state = {
openedDropdown = null;
}
并向您的下拉菜单发送一个回调函数:
dropdownClicked = openedDropdown => ev => {
this.setState({ openedDropdown })
}
<DropdownMenu text="New" count={127} disabled showDropdown={this.dropdownClicked('New')} menuOpen={this.state.openedDropdown === 'New'}/>
<DropdownMenu text="Only show" showDropdown={this.dropdownClicked('Only')} menuOpen={this.state.openedDropdown === 'Only'}>
<li>New</li>
<li>Old</li>
</DropdownMenu>
<DropdownMenu text="Other" showDropdown={this.dropdownClicked('Other')} menuOpen={this.state.openedDropdown === 'Other'}>
<li>one</li>
<li>two</li>
</DropdownMenu>
<DropdownMenu text="Sort by" showDropdown={this.dropdownClicked('Sort')} menuOpen={this.state.openedDropdown === 'Sort'}>
<li>Name</li>
<li>Age</li>
<li>Value</li>
</DropdownMenu>
我会为此使用redux。 https://redux.js.org/
该解决方案使您可以管理整个应用程序的状态。 它可以用于存储有关打开的下拉菜单的信息,并在必要时进行更改。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.