Javascript 如何打开和关闭btn点击下拉列表,但同时与外部点击关闭?

Javascript 如何打开和关闭btn点击下拉列表,但同时与外部点击关闭?,javascript,html,reactjs,Javascript,Html,Reactjs,我有一个下拉列表,在点击btn时打开 toggleAllCategories() { this.setState({ isOpenAllCategories: !this.state.isOpenAllCategories }); } 此外,在“外部单击”下拉列表关闭 handleClickOutside(event) { if (this.wrapperRef && !this.wrapperRef.contains(event.target))

我有一个下拉列表,在点击btn时打开

  toggleAllCategories() {
    this.setState({ isOpenAllCategories: !this.state.isOpenAllCategories });
  }
此外,在“外部单击”下拉列表关闭

  handleClickOutside(event) {
    if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
      this.toggleAllCategories();
    }
  }
但问题是我不能通过点击按钮来打开和关闭下拉列表

当我点击两次按钮时,下拉列表仍然打开,cus的外部点击实现

如何使ToggleDroondown在按钮上和关闭外部点击在同一时间

STACKBLITZ现场示例:

这是下拉列表和整个相关逻辑的组件和整个实现:

class AllCategories extends Component {
  constructor(props) {
    super(props);

    this.state = {
      allCategories: getAllCategoriesList(),
      isOpenAllCategories: false
    };
  }

  componentDidMount() {
    document.addEventListener('mousedown', this.handleClickOutside.bind(this));
  }

  componentWillUnmount() {
    document.removeEventListener('mousedown', this.handleClickOutside.bind(this));
  }

  setWrapperRef(node) {
    this.wrapperRef = node;
  }

  handleClickOutside(event) {
    if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
      this.toggleAllCategories();
    }
  }

  toggleAllCategories() {
    this.setState({ isOpenAllCategories: !this.state.isOpenAllCategories });
  }

  render() {
    return (
      <Fragment>
        <AllCategoriesButton toggleAllCategories={this.toggleAllCategories} />

        {this.state.isOpenAllCategories ? (
          <div className="all-categories-wrapper" ref={(node) => this.setWrapperRef(node)}>
            <div className="all-categories">
              <ul className="all-categories-list">
                <li className="all-categories-list-item">All Categories</li>
                {this.state.allCategories.map((category) => (
                  <li
                    className={`all-categories-list-item ${
                      category.selected ? 'all-categories-list-item-active' : ''
                    }`}
                  >
                    {category.name}
                  </li>
                ))}
              </ul>
            </div>
          </div>
        ) : (
          ''
        )}
      </Fragment>
    );
  }
}
class AllCategories扩展组件{
建造师(道具){
超级(道具);
此.state={
allCategories:getAllCategoriesList(),
isOpenAllCategories:错误
};
}
componentDidMount(){
document.addEventListener('mousedown',this.handleClickOutside.bind(this));
}
组件将卸载(){
document.removeEventListener('mousedown',this.handleClickOutside.bind(this));
}
setWrapperRef(节点){
this.wrapperRef=节点;
}
handleClickOutside(事件){
if(this.wrapperRef&&!this.wrapperRef.contains(event.target)){
this.toggleAllCategories();
}
}
toggleAllCategories(){
this.setState({isOpenAllCategories:!this.state.isOpenAllCategories});
}
render(){
返回(
{this.state.isOpenAllCategories(
this.setWrapperRef(节点)}>
  • 所有类别
  • {this.state.allCategories.map((category)=>(
  • {category.name}
  • ))}
) : ( '' )} ); } }
您可以使用
事件.target.tagName
检查触发单击的元素

因此,为了防止两次切换,您可以执行以下操作:

 handleClickOutside(event) {
    if (this.wrapperRef && !this.wrapperRef.contains(event.target) &&event.target.tagName.toLowerCase() !== 'button') {
      this.toggleAllCategories();
    }
  }

编辑: 另一种方法

  • 为按钮创建一个ref,并将其命名为
    buttonRef
现在将
handleClickOutside
更新为:

handleClickOutside(event) {
    if (this.wrapperRef && !this.wrapperRef.contains(event.target) &&event.target !== buttonRef.current) {
      this.toggleAllCategories();
    }
  }
这将是更合适的方式


希望这有帮助

在按钮单击的情况下,会触发两次
toggleAllCategories
。一个来自按钮点击,另一个来自
handleClickOutside
。您需要从一个位置调用它

是的,因为我需要能够在外部点击和按钮点击时关闭下拉列表。这意味着如果点击按钮区域,不会触发外部关闭?我可以检查点击标记的事件类别吗,而不是通过按钮类而不是按钮标签来处理它?对,如果你再次点击同一个按钮,你不想触发外部点击。我正在用另一种方法更新我的answeer。希望有帮助!