反应路由器导航多页和反应滚动

时间:2021-05-20 05:16:56

标签: javascript reactjs react-router-dom react-scroll

我正在尝试的是一个多页反应应用程序,我可以在其中导航页面(例如从主路由“/”到“/whitepape”或“privacyPolicy”),但我有 4 条不同的路由(“/” , 'services', 'features', 'contactUs') 在主路由 '/' 中使用 react-scroll 在导航栏中添加链接的 4 个组件之间滚动(这部分按预期工作)。

但是在页面之间导航,比如用白皮书页面或隐私政策页面完全替换所有 4 个组件,将导航栏和页脚放在同一位置,以便我可以导航回到主页。

这就是我遇到的任何帮助很感激我不确定我是否遵循正确的方法来实现我需要的东西。我一直在 React Native 中使用 React Navigation,它易于理解和直接,希望 react-router 如此直接,而不是 react-router 有点混乱。

App.js

function App() {
  return (
    <div className="App">
      <Navbar />
      <Switch>
        <Route path="/">
          <>
            <Hero />
            <Services />
            <Features />
            <ContactUs />
          </>
        </Route>
        <Route path="/whitepaper">
          <WhitePaper />
        </Route>
      </Switch>
      <Footer />
    </div>
  )
}

Navbar.js

import { Link } from 'react-scroll'
import { withRouter, Link as RouterLink } from 'react-router-dom'

const menuItems = [
  {
    menuTitle: 'Home',
    pageURL: '/',
    id: 'hero'
  },
  {
    menuTitle: 'Services',
    pageURL: '/services',
    id: 'services'
  },
  {
    menuTitle: 'Features',
    pageURL: '/features',
    id: 'features'
  },
  {
    menuTitle: 'Contact Us',
    pageURL: '/contactUs',
    id: 'contactUs'
  }
]

const Navbar = ({ history }) => {
  const classes = useStyles()
  const [anchorEl, setAnchorEl] = useState(null)
  const [showNav, setShowNav] = useState(false)
  const open = Boolean(anchorEl)
  const theme = useTheme()
  const isMobile = useMediaQuery(theme.breakpoints.down('sm'))
  const [isActive, setIsActive] = useState('/')

  useEffect(() => {
    setIsActive(history.location.pathname)
    window.addEventListener('scroll', () => {
      if (window.scrollY > 100) {
        setShowNav(true)
      } else {
        setShowNav(false)
      }
    })
    return () => {
      window.removeEventListener('scroll', () => setShowNav(false))
    }
  })

  const handleMenu = event => {
    setAnchorEl(event.currentTarget)
  }

  const handleMenuClick = pageURL => {
    history.push(pageURL)
    setAnchorEl(null)
  }

  const handleClose = () => {
    setAnchorEl(null)
  }

  const handleLinkClick = pageURL => {
    history.push(pageURL)
  }

  return (
    <div>
      <AppBar
        position="static"
        elevation={0}
        className={`${classes.appBar} ${
          showNav ? classes.appBarOnScroll : classes.appBar
        }`}>
        <Container>
          <Toolbar className={classes.toolbar}>
            <Link to="hero" smooth duration={1000}>
              <RouterLink to="/">
                <img src={logo} alt="Company Logo" className={classes.logo} />
              </RouterLink>
            </Link>
            {isMobile ? (
              <div>
                <IconButton
                  edge="start"
                  className={classes.menuButton}
                  color="inherit"
                  onClick={handleMenu}
                  aria-label="menu">
                  <MenuIcon />
                </IconButton>
                <Menu
                  className={classes.mobileMenu}
                  id="menu-appbar"
                  anchorEl={anchorEl}
                  anchorOrigin={{
                    vertical: 'top',
                    horizontal: 'right'
                  }}
                  keepMounted
                  transformOrigin={{
                    vertical: 'top',
                    horizontal: 'right'
                  }}
                  open={open}
                  onClose={handleClose}>
                  {menuItems.map(menuItem => {
                    const { menuTitle, pageURL, id } = menuItem
                    return (
                      <Link key={menuTitle} to={id} smooth duration={1000}>
                        <MenuItem
                          className={
                            isActive === pageURL
                              ? classes.mobileActiveMenuItem
                              : classes.mobileMenuItem
                          }
                          onClick={() => handleMenuClick(pageURL)}>
                          {menuTitle}
                        </MenuItem>
                      </Link>
                    )
                  })}
                </Menu>
              </div>
            ) : (
              <div className={classes.menu}>
                <Link
                  to="home"
                  smooth
                  duration={1000}
                  className={
                    isActive === '/' ? classes.menuActiveLink : classes.menuLink
                  }
                  variant="contained"
                  onClick={() => handleLinkClick('/')}>
                  Home
                </Link>
                <Link
                  to="services"
                  smooth
                  duration={1000}
                  className={
                    isActive === '/services'
                      ? classes.menuActiveLink
                      : classes.menuLink
                  }
                  variant="contained"
                  onClick={() => handleLinkClick('/services')}>
                  Services
                </Link>
                <Link
                  to="features"
                  smooth
                  duration={1000}
                  className={
                    isActive === '/features'
                      ? classes.menuActiveLink
                      : classes.menuLink
                  }
                  variant="contained"
                  onClick={() => handleLinkClick('/features')}>
                  Features
                </Link>
                <Link
                  to="contactUs"
                  smooth
                  duration={1000}
                  className={
                    isActive === '/contactUs'
                      ? classes.menuActiveLink
                      : classes.menuLink
                  }
                  variant="contained"
                  onClick={() => handleLinkClick('/contactUs')}>
                  ContactUs
                </Link>
              </div>
            )}
          </Toolbar>
        </Container>
      </AppBar>
    </div>
  )
}

export default withRouter(Navbar)

Footer.js

import { Link } from 'react-scroll'
import { Link as RouterLink } from 'react-router-dom'

const Footer = () => {
  const classes = useStyles()
  const icons = [
    {
      img: linkedin,
      alt: 'linkedin',
      url: 'https://www.linkedin.com/company/company'
    },
    {
      img: twitter,
      alt: 'twitter',
      url: 'https://twitter.com/company'
    },
    {
      img: instagram,
      alt: 'instagram',
      url: 'https://www.instagram.com/company/'
    },
    {
      img: facebook,
      alt: 'facebook',
      url: 'https://www.facebook.com/company/'
    }
  ]
  return (
    <div className={classes.footer}>
      <Container className={classes.container}>
        <Grid container spacing={4}>
          <Grid item md={3} xs={12}>
            <div className={classes.column}>
              <Link to="hero" smooth duration={1000}>
                <RouterLink to="/">
                  <img className={classes.logo} src={logo} alt="Company Logo" />
                </RouterLink>
              </Link>
            </div>
          </Grid>
          <Grid item md={3} xs={12}>
            <div className={classes.column}>
              <div>
                <Grid item>
                  <span className={classes.linksTitle}>USEFUL LINKS</span>
                </Grid>
                <Grid item className={classes.links}>
                  <RouterLink to="/whitepaper" replace className={classes.link}>
                    <span className={classes.span}>White Paper</span>
                  </RouterLink>
                </Grid>
                <Grid item className={classes.links}>
                  <a
                    href="mailto:xyz@comapmy.com"
                    className={classes.link}>
                    <span className={classes.span}>Email Our CEO</span>
                  </a>
                </Grid>
                <Grid item className={classes.links}>
                  <RouterLink to="/" className={classes.link}>
                    <span className={classes.span}>Privacy Policy</span>
                  </RouterLink>
                </Grid>
              </div>
            </div>
          </Grid>
          <Grid item md={3} xs={12}>
            <div className={classes.column}>
              {icons.map(icon => {
                return (
                  <a href={icon.url} key={icon.alt}>
                    <img
                      className={classes.icon}
                      src={icon.img}
                      alt={icon.alt}
                    />
                  </a>
                )
              })}
            </div>
          </Grid>
          <Grid item md={3} xs={12}>
            <div className={classes.top}>
              <Link to="hero" smooth duration={1000}>
                <RouterLink to="/">
                  <div>
                    <img src={top} alt="back to top" />
                    <p>Back To Top</p>
                  </div>
                </RouterLink>
              </Link>
            </div>
          </Grid>
        </Grid>
        <Grid container>
          <Grid item xs={12}>
            <div className={classes.footerBottom}>
              <p className={classes.copyright}>
                © 2021 Copyrights •{' '}
                <Link to="hero" smooth duration={1000}>
                  <RouterLink to="/" className={classes.company}>
                    <span>company.com</span>
                  </RouterLink>
                </Link>
              </p>
            </div>
          </Grid>
        </Grid>
      </Container>
    </div>
  )
}

export default Footer

1 个答案:

答案 0 :(得分:1)

Switch 组件中,路径顺序和特异性很重要。不过,这并不是在他们的文档中公开提及的细节。您希望将更具体的路径不太具体的路径之前排序。将 path 视为更多的前缀,您会看到“/”是所有路径的路径前缀。

Switch 返回并呈现它在其子节点中找到的第一个匹配路径。

只需反转路径的顺序,使 "/whitepaper" 列在更一般/不太具体的 "/" 路径之前。

function App() {
  return (
    <div className="App">
      <Navbar />
      <Switch>
        <Route path="/whitepaper">
          <WhitePaper />
        </Route>
        <Route path="/">
          <>
            <Hero />
            <Services />
            <Features />
            <ContactUs />
          </>
        </Route>
      </Switch>
      <Footer />
    </div>
  )
}