24

选择项目后如何使菜单折叠?

我不知道如何让它在小提琴上工作,但这就是我会做的? https://jsfiddle.net/vjeux/kb3gN/

import React from 'react';
import {Navbar, Nav, NavItem, NavDropdown, DropdownButton, MenuItem, CollapsibleNav} from 'react-bootstrap';

export default class App extends React.Component {

    constructor(props) {
      super(props);
      this.onSelect = this.onSelect.bind(this);
      this.toggleNav = this.toggleNav.bind(this);
      // this.state = {navExpanded: false};
    }

    onSelect(e){
        console.log('OnSelect')
        // console.log(this.state.navExpanded);
        // this.setState({navExpanded: false});
    }

    toggleNav(){console.log('toggle...')};

    // <Navbar inverse fixedTop toggleNavKey={0} navExpanded={this.state.navExpanded} onToggle={() => this.toggleNav()}>
    // <Navbar inverse fixedTop toggleNavKey={0} navExpanded={this.state.navExpanded} >

    render() {
        return (

          <Navbar inverse fixedTop toggleNavKey={0} >
            <Nav right eventKey={0} onSelect={this.onSelect} > {/* This is the eventKey referenced */}
              <NavItem eventKey={1} href="#">Link</NavItem>
              <NavItem eventKey={2} href="#">Link</NavItem>
            </Nav>
          </Navbar>     

      )

    }

    componentDidMount() {

    }
}

React.render(<App />, document.getElementById('example'));
4

12 回答 12

67

对于 2020 年来到这里并使用Hooks的任何人,也许您正在使用react-router, 因此,您使用的Nav.Link导航栏的默认组件不是.Linkreact-router

你发现了什么?这导致移动菜单无法按预期工作,并且在单击链接后没有关闭,并且似乎没有任何效果。

这是我对该问题的“简单”解决方案(使用挂钩):

首先我们设置一个钩子:

const [expanded, setExpanded] = useState(false);

其次Navbar我们添加这个道具:

<Navbar expanded={expanded}>

现在我们可以控制菜单的可见性,在“第一次”加载时它会被隐藏。

第三,我们向切换处理程序添加一个onClick事件来更改菜单可见性状态:

<Navbar.Toggle onClick={() => setExpanded(expanded ? false : "expanded")} />

第四,我们将 prop从导航栏中的 react-router添加onClick={() => setExpanded(false)}到所有组件。Link

利润!我发誓,经过 1 个多小时的互联网漫游是我找到的最简单、最干净的解决方案。

于 2019-10-23T20:19:24.247 回答
19

我从这个链接找到了解决方案 https://github.com/react-bootstrap/react-bootstrap/issues/1301

我将把上面链接的示例代码放在这里

const Menu = React.createClass ({
  getInitialState () {
    return {
      navExpanded: false
    }
  },

  setNavExpanded(expanded) {
    this.setState({ navExpanded: expanded });
  },

  closeNav() {
    this.setState({ navExpanded: false });
  },

  render() {
    return (
      <div>
        <Navbar onToggle={this.setNavExpanded}
                expanded={this.state.navExpanded}>
          <Navbar.Header>
            <Navbar.Brand>
              <Link to="some url">Main</Link>
            </Navbar.Brand>
            <Navbar.Toggle />
          </Navbar.Header>
          <Navbar.Collapse>
            <Nav onSelect={this.closeNav}>
              { this.renderMenuItem() }
            </Nav>
          </Navbar.Collapse>
        </Navbar>
      </div>
    )
  }
于 2017-06-25T18:31:44.103 回答
7

与问题略有相关,可能对某人有帮助这是我在菜单外单击时关闭导航栏所做的

class Menu extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isNavExpanded: false
    };
  
    this.setIsNavExpanded = (isNavExpanded) => {
      this.setState({ isNavExpanded: isNavExpanded });
    }
  
    this.handleClick = (e) => {
      if (this.node.contains(e.target)) {
        // if clicked inside menu do something
      } else {
        // If clicked outside menu, close the navbar.
        this.setState({ isNavExpanded: false });
      }
    }
  }
  componentDidMount() {
    document.addEventListener('click', this.handleClick, false);      
  }

  componentWillUnmount() {
    document.removeEventListener('click', this.handleClick, false);
  }

  render() {
    return (
      <div ref={node => this.node = node}
        <Navbar collapseOnSelect
           onToggle={this.setIsNavExpanded}
           expanded={this.state.isNavExpanded}
           >
          <Navbar.Collapse>
            // Nav Items
          </Navbar.Collapse>
        </Navbar>
      </div>
    )
  }

于 2019-04-02T10:56:58.020 回答
4

<Navbar collapseOnSelect ... >应该做的工作,但它的工作不稳定:(

于 2019-05-29T00:30:02.100 回答
4
import React, { Component } from "react";
import { Navbar, Nav, Container } from 'react-bootstrap';
import logo from '../assets/logo.png';
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";

export default class Menu extends Component {
  constructor(props) {
    super(props);

    this.state = {
      navExpanded: false
    };
  }

  setNavExpanded = (expanded) => {
    this.setState({ navExpanded: expanded });
  }

  setNavClose = () => {
    this.setState({ navExpanded: false });
  }

  render() {
    return (
      <Navbar bg="dark" variant="dark" expand="lg" onToggle={this.setNavExpanded} expanded={this.state.navExpanded}>
        <Container>
          <Navbar.Brand>
              <Link to={"/"} className="navbar-brand"><img src={logo} height="30"></img></Link>
          </Navbar.Brand>          
          <Navbar.Toggle aria-controls="basic-navbar-nav" />
          <Navbar.Collapse id="basic-navbar-nav">
            <Nav className="mr-auto" onClick={this.setNavClose}>
              <Link to={"/"} className="nav-link">Home</Link>
              <Link to={"/"} className="nav-link">Contact</Link>
            </Nav>          
          </Navbar.Collapse>
        </Container>
      </Navbar>
    );
  }
}
于 2020-07-26T22:48:42.463 回答
4

我喜欢@Josep Vidal 的帖子,因为我遇到了同样的问题,但是,我对他的回答有一点小改动。虽然他的方法在这一点上确实是最好的,但我相信如果不是

<Navbar.Toggle onClick={() => setExpanded(expanded ? false : "expanded")} />

我们做了

<Navbar.Toggle onClick={() => setExpanded((prevExpanded) => (prevExpanded = !prevExpanded)) />

另外,不需要把 onClick={() => setExpanded(false)} 所有的Link组件都放在,我们可以简单地把它放在父组件上Nav

于 2020-04-28T17:30:31.427 回答
3

这里有很多答案,但截至今天的修复非常简单。无需使用状态或点击事件。这是假设您正在渲染Link每个Nav.Link.

在此处添加collapseOnSelect道具。

<Navbar collapseOnSelect expand="false">

并将eventKey道具添加到每个Nav.Link.

<Nav.Link as={Link} to="/page1" eventKey="1">Page 1</Nav.Link>
<Nav.Link as={Link} to="/page2" eventKey="2">Page 2</Nav.Link>
于 2021-11-11T09:48:26.460 回答
1

这是我的解决方案,它使用本机 Bootstrap 菜单功能。原因是折叠菜单时有更多相关行为,例如更改汉堡菜单图标,因为它具有可切换类“折叠”和布尔也用于属性区域扩展,因此。

所以......我们让默认的 Bootstrap 功能处理该部分,我们只需要添加功能以使用相同的功能折叠菜单,但只有在展开菜单时才应该触发(否则我们会有不希望的冲突行为。 )

我们需要一个 const "expanded" 来确定可折叠/可展开菜单的状态,以防止在桌面设备上查看站点并且完整菜单已经可见时它无法展开。

const [expanded, setExpanded] = useState("")

这是我们在 navbar-toggler 按钮上使用 click 事件设置的唯一 const。它要么展开要么不展开(我们处理这个)并且折叠或不折叠(Bootstrap 处理这个。)

<button
    className={"navbar-toggler collapsed" + expanded}
    type="button"
    data-bs-toggle="collapse"
    data-bs-target="#navbar"
    aria-controls="navbar"
    aria-expanded="false"
    aria-label="Toggle navigation"
    onClick={() => setExpanded(expanded ? "" : " expanded")}
>

我们现在只有在菜单真正展开时才处于展开状态,并且由于 navbar-toggler 按钮仅显示在移动设备上(取决于您的配置),因此在桌面设备上不会发生冲突。

现在我们只需要使用默认的 Bootstrap 功能来切换菜单,因此在您想要充当切换器的每个项目上,您都必须添加该功能。这将处理所有引导行为,因此我们不需要额外的钩子。

<li className="nav-item" data-bs-toggle={expanded && "collapse"} data-bs-target="#navbar" aria-controls="navbar" onClick={() => setExpanded("")}>

这样做是仅在菜单展开时触发切换功能,因此仅在移动设备上。没有任何冲突。

我不建议将其添加到容器 div 中,因为如果菜单包含带有子项的菜单或可能是搜索表单,这也会触发切换。

期待评论和改进。

于 2021-01-29T12:41:50.677 回答
1

根据上面的答案和一些在线最佳实践,我想出了一些很棒的代码并在这里分享。Bellow 只是一个导航栏组件,可以轻松选择并使用它,因为它是响应式媒体,宽度设置为 500 像素

import './navbar.css'
import { useState, useEffect } from 'react'
import { Route, BrowserRouter as Router, Switch, Link} from 'react-router-dom'
import Home from './Pages/Home'
import About from './Pages/About'
import Contact from './Pages/Contact'
import Product from './Pages/Product'

const Navbar = () => {
    const [screenWidth, setScreenWidth] = useState(window.innerWidth)
    const [toggleMenu, setToggleMenu] = useState(false)

    function toggle(){
        setToggleMenu( preValue => (!preValue))
    }
     
    useEffect(() => {

        const changeWidth = () => {
            setScreenWidth(window.innerWidth);
          }
          window.addEventListener('resize', changeWidth)

        return () => {
            window.removeEventListener('resize', changeWidth)
        }

    },[])

    return (
        <Router>
            <nav>
                {// better to use Link component instead of href as Link will keep entire operation at client side and not reeload the page
                }
            {
                (toggleMenu || screenWidth >= 500 ) && (
                <ul className='list'>
                <li className='items'><Link onClick={() => setToggleMenu(false)} to='/'>Home</Link></li>
                <li className='items'><Link onClick={() => setToggleMenu(false)} to='/about'>About Us</Link></li>
                <li className='items'><Link onClick={() => setToggleMenu(false)} to='/product'>Product</Link></li>
                <li className='items'><Link onClick={() => setToggleMenu(false)} to='/contact'>Contact Us</Link></li>
            </ul>
                )

            }
            <button className='btn'
            onClick={toggle}>Btn</button>
        </nav>

        <Switch>
            <Route path='/contact'><Contact /></Route>
            <Route path='/product'><Product /></Route>
            <Route path='/about'><About /></Route>
            <Route path='/'><Home /></Route>
        </Switch>
        </Router>
    )
}

export default Navbar
于 2021-04-28T06:47:42.020 回答
0

对于那些使用 react hooks 的人,基于上面的@Alongkorn Chetasumon:

  const wrapperRef = useRef(null);
  const [navExpanded, setNavExpanded] = useState();
  const closeNav =()=> {
    setNavExpanded(false);
  }
  useEffect(() => {
    /**
     * Alert if clicked on outside of element
     */
    function handleClickOutside(event) {
      if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
        //alert("You clicked outside of me!");
        closeNav();
      }
    }

    // Bind the event listener
    document.addEventListener("mousedown", handleClickOutside);
    return () => {
        // Unbind the event listener on clean up
        document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [wrapperRef]);
于 2021-03-23T09:26:23.390 回答
0

对我来说,约瑟夫的决定是我实施了所有四点。但我还有其他妆容:

            <Navbar expanded={expanded} bg="light" expand="lg" className="p-3">
            <Navbar.Brand href="/"><img src={CarLogo} alt="Tim-Tim auto" title="Tim-Tim auto" /></Navbar.Brand>
            <Navbar.Toggle onClick={() => setExpanded(expanded ? false : "expanded")} aria-controls="basic-navbar-nav" />
                <Navbar.Collapse id="basic-navbar-nav" className="justify-content-end">
                    <Nav> 
                        <Nav.Item><NavLink onClick={() => setExpanded(false)} exact to='/'>Home</NavLink></Nav.Item>
                        <Nav.Item><NavLink onClick={() => setExpanded(false)} to='/Cars'>Cars</NavLink></Nav.Item>
                        <Nav.Item><NavLink onClick={() => setExpanded(false)} to='/about'>About</NavLink></Nav.Item>
                        <Nav.Item><NavLink onClick={() => setExpanded(false)} to='/news'>News</NavLink></Nav.Item>
                        <Nav.Item><NavLink onClick={() => setExpanded(false)} to='/contacts'>Contacts</NavLink></Nav.Item>
                    </Nav>
                </Navbar.Collapse>
            </Navbar>
于 2019-11-12T10:00:05.937 回答
0

这是一个老问题,我不知道这个选项当时是否可用,但在导航栏组件中使用collapseOnSelect 。这是正确且非常快速的解决方案!

<Navbar **collapseOnSelect** className="header" bg="light" expand="lg">
      <Nav.Link className="navbar-link navbar-link-header" as={NavLink} to="/">
        <Navbar.Brand>
         
        </Navbar.Brand>
      </Nav.Link>

      <Navbar.Toggle aria-controls="basic-navbar-nav" />

      <Navbar.Collapse id="basic-navbar-nav">
        <Nav className="me-auto">
          <Nav.Link className="navbar-link" as={NavLink} to="/resume">
        
          </Nav.Link>
          <Nav.Link className="navbar-link" as={NavLink} to="/portfolio">
         
          </Nav.Link>
          <Nav.Link className="navbar-link" as={NavLink} to="/blogs">
         
          </Nav.Link>
          <Nav.Link className="navbar-link" as={NavLink} to="/contact">
        
          </Nav.Link>
        </Nav>
      </Navbar.Collapse>

    </Navbar>
于 2021-09-30T18:48:07.160 回答