简体   繁体   中英

Need help making clickable dropdown menu toggle off while simultaneously toggling the different target dropdown

I have a nav bar with dropdown buttons that toggle on with button press and off with clicking outside the window. When you hover over each button, the text is underlined in yellow. When you click the button, a list of other buttons drops down beneath it. If the user decides to open another drop down while one is already open, it takes two clicks. One to click out of the current dropdown window, and one to click on the new button. I would like it to have a case of clicking off on a navbutton to simultaneously close the current window and open the new target window.

Another small detail that I'm struggling to implement is to make the clicked navbar button toggle on the same underlined style that appears when hovering. I'm struggling in both case to target and reference the right element.

class NavBar extends Component {
  constructor(){
    super();
    this.state =  { displayMenu: '' }
    this.showDM = this.showDM.bind(this);
    this.hideDM = this.hideDM.bind(this);

  }

  showDM (type) {
   this.setState({ displayMenu: type }, () => {
      document.addEventListener('click', this.hideDM);
    });
  }

  hideDM (ev) {
    this.setState({ displayMenu: '' }, () => {
      document.removeEventListener('click', this.hideDM)
    });
  }

  render() {
    return (
      <header>
        <div className="image">
          <a href="./"><img className="logo" src={Logo} alt="Pre-Collegiate Program Yangon" /></a>
        </div>
        <div className="right">
          <div className="text" >
            <h1 className="pcp"><strong>The Pre-Collegiate Program </strong>of Yangon</h1>
          </div>
          <div className="navbar">
            <div className="dropdown">
              <button id="about" onClick={() => this.showDM("about")} className="dropbtn">About 
                <i className="fa fa-caret-down"></i>
              </button>
              { this.state.displayMenu === "about" ? ( 
              <div className="dropdown-content" id="ddc">
                <a href="#mission"><Link to="/mission">Mission</Link></a>
                <a href="#history"><Link to="/history">History</Link></a>
                <a href="#alumni"><Link to="/alumni">Alumni</Link></a>
              </div>
              ):
              ( 
                null 
              )
              }
            </div>
            <div className="dropdown">
              <button  onClick={() => this.showDM("academics")} className="dropbtn">Academics 
                <i className="fa fa-caret-down"></i>
              </button>
              { this.state.displayMenu === "academics" ? (
              <div className="dropdown-content" id="ddc">
                <a href="#liber-alarts"><Link to="/liberal-arts">Liberal Arts Education</Link></a>
                <a href="#faculty-and-staff"><Link to="/faculty-and-staff">Our Faculty and Staff</Link></a>
                <a href="#curriculum"><Link to="/curriculum">Our Curriculum</Link></a>
                <a href="#study-abroad"><Link to="/study-abroad">Study Abroad</Link></a>
              </div>
              ):
              ( 
                null 
              )
              }

You can do something like this. With this you will separate concerns, have less code, it will be more readable and easier to maintain.

class NavBar extends Component {
    constructor(){
      super();       

        this.state = {
            menu: [
                {
                    type: 'about',
                    isOpen: false,
                    links: [
                        {
                            title: "Mission",
                            link: "/mission"
                        },
                        {
                            title: "History",
                            link: "/history"
                        },
                        {
                            title: "Alumni",
                            link: "/alumni"
                        }
                    ]
                },
                {
                    type: 'academics',
                    isOpen: false,
                    links: [
                        {
                            title: "Liberal Arts Education",
                            link: "/liberal-arts"
                        },
                        {
                            title: "Our Faculty and Staff",
                            link: "/faculty-and-staff"
                        },
                        {
                            title: "Our Curriculum",
                            link: "/curriculum"
                        },
                        {
                            title: "Study Abroad",
                            link: "/study-abroad"
                        }
                    ]
                }
            ],
            isActive: null
        };
    }

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

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

    activateMenu = (type) => {
        this.setState(prevState => {
            prevState.displayMenu = type;
            for(let i=0; i<prevState.menu.length; i++){
                prevState.menu[i].isOpen = prevState.menu[i].type == type ? true : false;
            }
            return prevState;
        });
    }

    setMenuWrapper = node => {
        this.setState({isActive: node});
    }

    handleClickOutside = e => {         
        if (this.state.isActive && !this.state.isActive.contains(e.target)) {
            this.setState(prevState => {
                for(let i=0; i<prevState.menu.length; i++){
                    prevState.menu[i].isOpen = false;
                }
                return prevState;
            })
        }
    }

    render() {
        return (
            <header>
                <div className="image">
                    <a href="./"><img className="logo" src="logo" alt="Pre-Collegiate Program Yangon" /></a>
                </div>
                <div className="right">
                    <div className="text" >
                        <h1 className="pcp"><strong>The Pre-Collegiate Program </strong>of Yangon</h1>
                    </div>
                    <div className="navbar">
                        <div ref={this.setMenuWrapper} id="set-menu-wrapper">
                            { this.state.menu.map(m => (
                                <div className="dropdown">
                                    <button id="about" onClick={() => this.activateMenu(m.type)} className="dropbtn">{m.type} 
                                    <i className="fa fa-caret-down"></i>
                                    </button>
                                    { m.isOpen && 
                                        <div className="dropdown-content" id="ddc">
                                            { m.links.map(l => (
                                                <a href={l.link}>{l.link}</a>
                                            ))}
                                        </div>
                                    }
                                </div>
                            ))}
                        </div>
                    </div>
                </div>
            </header>
        );
    };
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM