[英]Multiple dropdowns in ReactJS, only one open at a time
I have two dropdowns being passed in as props to components. 我有两个下拉菜单作为对组件的传递。 I can control both with seperate states but I think this can all be done with one state?
我可以用单独的状态来控制这两个状态,但是我认为可以用一个状态来完成全部操作吗?
Header 标头
import React from 'react';
import DarkLabel from './DarkLabel';
import HeaderDropdown from './HeaderDropdown';
export default class Header extends React.Component {
componentWillMount() {
this.setState({
listOpen: false
})
}
render() {
...
return (
<div className="row header">
<div className="col-xs-10">
<DarkLabel classExtra="dark-label-lg" icon="/images/system-icons/document_empty.png"
content={taskCode}/>
<DarkLabel classExtra="dark-label-2x dark-label-lg" icon="/images/system-icons/building.png"
dropdown=<HeaderDropdown data={this.props.enquiry.entity ? this.props.enquiry.entity : null}/>
content={this.props.enquiry.entity ? this.props.enquiry.entity.name : 'ERROR'}
right_icon="/images/system-icons/bullet_arrow_down.png"/>
<DarkLabel classExtra="dark-label-md" icon="/images/system-icons/ceo.png"
dropdown=<HeaderDropdown data={this.props.enquiry.contact ? this.props.enquiry.contact : null}/>
content={this.props.enquiry.contact ? this.props.enquiry.contact.firstName + ' ' + this.props.enquiry.contact.lastName : '-'}
right_icon="/images/system-icons/bullet_arrow_down.png"/>
<DarkLabel classExtra="flag"
content={'/images/flags/large/'+this.props.enquiry.entity.country.countryCode+'.png'}
right_icon="/images/system-icons/cog.png" right_icon_callback={this.handleAddressModal.bind(this)}/>
</div>
</div>
)
}
}
HeaderDropdown HeaderDropdown
import React from 'react'; 从'react'导入React;
export default class HeaderDropdown extends React.Component {
componentWillMount() {
}
render() {
return (
<div>
<div className="dark-label-dropdown">
Test
</div>
</div>
);
}
}
How can I make it so only one can be open at a time and close all others if a different one is clicked? 我如何才能做到这样,一次单击只能打开一个,如果单击另一个按钮,则关闭所有其他按钮? Do I need to store something from 'this' when I bind a click event to HeaderDropdown?
当我将Click事件绑定到HeaderDropdown时,是否需要存储来自“ this”的内容?
I have missed something from the question. 我错过了这个问题。 This needs to happen when the user clicks on right_icon in the DarkLabel.
用户在DarkLabel中单击right_icon时,就需要发生这种情况。
DarkLabel 黑暗标签
import React from 'react';
export default class DarkLabel extends React.Component {
componentWillMount() {
}
truncate(limit) {
...
}
render() {
var icon = '', content = '';
var rightIcon = '';
...
return (
<div className={'pull-left dark-label-wrapper '+this.props.classExtra}>
{icon}
<div>{content}</div>
{rightIcon}
{this.props.dropdown}
</div>
);
}
}
What you could do is add a onClick
method to your HeaderDropdown
and in your Header
handle the state for that. 您可以做的是将一个
onClick
方法添加到HeaderDropdown
并在Header
处理该状态。 The proper way would be using a store of some kind (redux) but that might be out of scope for this example. 正确的方法是使用某种类型的存储(redux),但这在本示例中可能超出范围。
So in short I suggest you alter you Header to this: 简而言之,我建议您将标题更改为:
import React from 'react';
import DarkLabel from './DarkLabel';
import HeaderDropdown from './HeaderDropdown';
export default class Header extends React.Component {
componentWillMount() {
this.setState({
listOpen: false,
activeDropdown: 1
})
}
render() {
const headerDropdownA = (
<HeaderDropdown
data={...}
onClick={() => this.setState({activeDropDown: 1})}
isActive={this.state.activeDropdown === 1}
/>
)
const headerDropdownA = (
<HeaderDropdown
data={...}
onClick={() => this.setState({activeDropDown: 2})}
isActive={this.state.activeDropdown === 2}
/>
)
return (
<div className="row header">
<div className="col-xs-10">
<DarkLabel classExtra="..."
dropdown={headerDropdownA}
content={...}
right_icon="/images/system-icons/bullet_arrow_down.png"/>
<DarkLabel classExtra="..."
dropdown={headerDropdownB}
content={...}
right_icon="/images/system-icons/bullet_arrow_down.png"/>
</div>
</div>
)
}
}
I added a state for the current active dropdown. 我为当前的活动下拉列表添加了状态。 In your dropdown you can then access the active state with
this.props.isActive
. 然后,您可以在此下拉列表中使用
this.props.isActive
访问活动状态。
But propably this will not already be sufficient since every click will toggle the dropdown again, also when you click the options? 但这可能还不够,因为每次单击都将再次切换下拉菜单,甚至在您单击选项时也是如此? But it might give you a good starting point.
但这可能会为您提供一个良好的起点。
You can create a high-order-component that will detect clicks outside of your component eg 您可以创建一个高阶组件,以检测组件外部的点击,例如
import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';
const clickOutsideEvents = [ 'mousedown', 'touchstart' ];
const isDescendant = ( el, target ) => target !== null ? el === target || isDescendant( el, target.parentNode ) : false;
export default class ClickOutside extends Component {
static propTypes =
{
children : PropTypes.node,
onClickOutside : PropTypes.any,
};
componentDidMount()
{
if ( !this.props.onClickOutside ) return;
clickOutsideEvents.forEach( e => document.addEventListener( e, this.handleClickOutside ) )
}
/**
* Remove the listener in case the props change and there is not ClickAway handler
* @param { Object } prevProps
*/
componentDidUpdate( prevProps )
{
if ( prevProps.onClickOutside !== this.props.onClickOutside )
{
clickOutsideEvents.forEach( e => document.removeEventListener( e, this.handleClickOutside ) );
if ( this.props.onClickOutside )
{
clickOutsideEvents.forEach( e => document.addEventListener( e, this.handleClickOutside ) )
}
}
}
/**
* Remove listeners when Component unmount
*/
componentWillUnmount()
{
clickOutsideEvents.forEach( e => document.removeEventListener( e, this.handleClickOutside ) );
}
/**
* Call callback on ClickAway and pass the event
* @param event
*/
handleClickOutside = ( e ) =>
{
const el = ReactDOM.findDOMNode( this );
if ( document.documentElement.contains( e.target ) && !isDescendant( el, e.target ) )
{
this.props.onClickOutside( e );
}
};
/**
* Render the Elements that are Wrapped by the ClickAway
*/
render()
{
return this.props.children;
}
}
Then wrap your dropdowns with this HOC and set the state of the component based on that 然后使用此HOC包装您的下拉列表,并根据该状态设置组件的状态
eg 例如
setDropdownState(){
this.setState({ listOpen: false });
}
render(){
return(<ClickOutside onClickOutside={ this.setDropdownState.bind( this ) }>
<HeaderDropdown listOpen={ this.state.listOpen }>
</ClickOutside>)
}
You can check this implementation https://github.com/AvraamMavridis/react-clickoutside-component 您可以检查此实现https://github.com/AvraamMavridis/react-clickoutside-component
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.