首页 > 解决方案 > React JS 中的两个固定导航栏

问题描述

我有一个已经固定到顶部的导航栏,看起来像这样: 在此处输入图像描述

现在我想在此之上再添加一个导航,它应该看起来像这样: 在此处输入图像描述

NavBars 应该固定在顶部,第一个的高度应该比第二个略小。我现在使用的代码是:

<Navbar variant="light" fixed="top" expand="lg" className="pt-4 pb-4">
    <Container>
        <Navbar.Brand href="/"><Image src={logo}></Image></Navbar.Brand>
        <Navbar.Toggle aria-controls="basic-navbar-nav" />
        <Navbar.Collapse id="basic-navbar-nav">
            <Nav className="mr-auto">
                <Nav.Link as={Link} to="/" className="ml-xl-4">Home</Nav.Link>
                <Nav.Link className="ml-xl-4">Shop</Nav.Link>
                <Nav.Link className="ml-xl-4">Sale</Nav.Link>
            </Nav>
            <Form inline>
                <FormControl type="text" placeholder="Search" className="mr-sm-5" />
            </Form>
            <Nav.Link as={Link} to="/"><Image src={accountIcon}></Image></Nav.Link>
            <Nav.Link as={Link} to="/cart" className="pr-0"><Image src={cartIcon}></Image></Nav.Link>
        </Navbar.Collapse>
    </Container>
</Navbar>

我正在使用 FontAwesome、StyledIcons、StyledComponents 和 ReactBootstrap。现在我无法在现有导航栏的顶部添加另一个导航栏。我试图在容器内创建另一个导航,但它失败了。请指导我对齐两个导航栏。

标签: reactjsreact-bootstrapstyled-components

解决方案


我离开 UI 库的原因之一是它们在外观定制方面可能会限制您可以做的事情。我经常发现外观定制的越多,我编写的 CSS/样式覆盖就越多。有些组件对于同一个组件会有完全不同的布局和不同的类,这意味着更多的 CSS 覆盖!因此,这种来回的斗争是我强烈建议利用 CSS-in-JS 的强大功能的主要原因之一(例如@emotionstyled-components等等)。

不过,这是一个工作演示

编辑导航栏顶部固定

或者

预览https ://7m0hn.csb.app/

我使用 Typescript 而不是普通的 Javascript,因为 VSCode 允许您将鼠标悬停在组件上以查看JSDoc描述(您可能需要向下滚动才能在对话框中查看描述)。按住ctrl鼠标左键单击组件时,将在同一选项卡中打开预览!


另一种方法是手动将classNames 添加到 ReactBootstrap 组件并应用 CSS 覆盖。在这种情况下,底部栏将是:

position: fixed; // locks it to screen 
top: 30px; // at this position (factoring in the height of the top bar)

但是同样,这不会像编写自己的可重用组件那样灵活。您可能会发现自己创建了许多类来为不同的页面/屏幕布局/主题设置相同的组件样式(例如 this DOM与 this DOM;或者,甚至与仅使用 UI 库的这个DOM相比)。


固定/index.ts

import styled from "@emotion/styled";

/**
 * The Fixed component is a custom styled component to mainly adjust related 'fixed: position" CSS properties.
 *
 * @param background - sets 'background' CSS property (default: "transparent").
 * @param bottom - sets 'bottom' CSS property (default: undefined).
 * @param height - sets 'height' CSS property (default: "auto").
 * @param left - sets 'left' CSS property (default: undefined).
 * @param padding - sets 'padding' CSS property (default: "0px").
 * @param right - sets 'right' CSS property (default: undefined).
 * @param top - sets 'top' CSS property (default: undefined).
 * @param width - sets 'width' CSS property (default: "100%").
 */
const Fixed = styled.div<{
  background?: string;
  bottom?: string;
  height?: string;
  left?: string;
  padding?: string;
  right?: string;
  top?: string;
  width?: string;
}>`
  position: fixed;
  display: flex;
  align-items: center;
  width: 100%;
  background: ${({ background }) => background || "transparent"};
  border-bottom: 2px solid #ccc;
  height: ${({ height }) => height || "auto"};
  padding: ${({ padding }) => padding || "0px"};
  top: ${({ top }) => top};
  right: ${({ right }) => right};
  bottom: ${({ bottom }) => bottom};
  left: ${({ left }) => left};
  width: ${({ width }) => width || "100%"};
`;

export default Fixed;

弹性/索引.ts

import styled from "@emotion/styled";

/**
 * The Flex component is a custom styled component to mainly set 'flex' CSS properties.
 *
 * @param align - sets 'align-items' CSS property (default: "stretch").
 * @param justify - sets 'justify-content' CSS property (default: "flex-start").
 * @param padding - sets 'padding' CSS property (default: "0px").
 * @param width - sets 'width' CSS property (default: "100%").
 */
const Flex = styled.div<{
  align?:
    | "stretch"
    | "center"
    | "flex-start"
    | "flex-end"
    | "baseline"
    | "initial"
    | "inherit";
  justify?:
    | "flex-start"
    | "flex-end"
    | "center"
    | "space-between"
    | "space-around"
    | "space-evenly";
  padding?: string;
  width?: string;
}>`
  display: flex;
  justify-content: ${({ justify }) => justify || "flex-start"};
  align-items: ${({ align }) => align || "stretch"};
  padding: ${({ padding }) => padding || "0px"};
  width: ${({ width }) => width || "100%"};
`;

export default Flex;

导航栏/index.tsx

import * as React from "react";
import Nav from "react-bootstrap/Nav";
import NavDropdown from "react-bootstrap/NavDropdown";
import Navbar from "react-bootstrap/Navbar";
import Form from "react-bootstrap/Form";
import FormControl from "react-bootstrap/FormControl";
import { IoPersonOutline } from "react-icons/io5";
import { GiShoppingCart } from "react-icons/gi";
import Fixed from "../Fixed";
import Flex from "../Flex";

export type eventKey = string | null;

const TopNavBar = () => {
  const [language, setLanguage] = React.useState<eventKey>("DE");
  const [currency, SetCurrency] = React.useState<eventKey>("€ EUR");

  const handleLanguageChange = React.useCallback((eventKey: eventKey) => {
    setLanguage(eventKey);
  }, []);

  const handleCurrencyChange = React.useCallback((eventKey: eventKey) => {
    SetCurrency(eventKey);
  }, []);

  return (
    <>
      <Navbar className="navbar-top" fixed="top">
        <Flex justify="flex-end" padding="0 20px 0 0">
          <NavDropdown
            onSelect={handleLanguageChange}
            alignRight
            title={language}
            id="basic-nav-dropdown"
          >
            <NavDropdown.Item eventKey="EN">EN</NavDropdown.Item>
            <NavDropdown.Item eventKey="ES">ES</NavDropdown.Item>
            <NavDropdown.Item eventKey="DE">DE</NavDropdown.Item>
            <NavDropdown.Item eventKey="JP">JP</NavDropdown.Item>
          </NavDropdown>
          <NavDropdown
            onSelect={handleCurrencyChange}
            alignRight
            title={currency}
            id="basic-nav-dropdown"
          >
            <NavDropdown.Item eventKey="€ EUR">€ EUR</NavDropdown.Item>
            <NavDropdown.Item eventKey="£ GBP">£ GBP</NavDropdown.Item>
            <NavDropdown.Item eventKey="¥ JPY">¥ JPY</NavDropdown.Item>
            <NavDropdown.Item eventKey="$ USD">$ USD</NavDropdown.Item>
          </NavDropdown>
        </Flex>
      </Navbar>
      <Fixed background="#fff" padding="5px 60px 0 20px" top="30px">
        <Flex justify="flex-start">
          <Navbar.Brand href="/">Brand</Navbar.Brand>
        </Flex>
        <Flex justify="center">
          <Form inline>
            <FormControl
              type="text"
              placeholder="Search"
              className="search-box"
            />
          </Form>
        </Flex>
        <Flex justify="flex-end">
          <Nav.Link>
            <IoPersonOutline />
          </Nav.Link>
          <Nav.Link className="pr-0">
            <GiShoppingCart />
          </Nav.Link>
        </Flex>
      </Fixed>
    </>
  );
};

export default TopNavBar;

应用程序.tsx

import Navbar from "./Navbar";
import "bootstrap/dist/css/bootstrap.min.css";
import "./styles.css";

const App = () => (
  <div className="app">
    <Navbar />
    <h1>Hello CodeSandbox</h1>
    <h2>Start editing to see some magic happen!</h2>
    <p>
      Curabitur aliquet quam id dui posuere blandit. Nulla porttitor accumsan
      tincidunt. Nulla porttitor accumsan tincidunt. Curabitur arcu erat,
      accumsan id imperdiet et, porttitor at sem. Vestibulum ante ipsum primis
      in faucibus orci luctus et ultrices posuere cubilia Curae; Donec velit
      neque, auctor sit amet aliquam vel, ullamcorper sit amet ligula.
      Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere
      cubilia Curae; Donec velit neque, auctor sit amet aliquam vel, ullamcorper
      sit amet ligula. Vestibulum ac diam sit amet quam vehicula elementum sed
      sit amet dui. Vestibulum ante ipsum primis in faucibus orci luctus et
      ultrices posuere cubilia Curae; Donec velit neque, auctor sit amet aliquam
      vel, ullamcorper sit amet ligula. Cras ultricies ligula sed magna dictum
      porta. Pellentesque in ipsum id orci porta dapibus.
    </p>
    <p>
      Proin eget tortor risus. Donec sollicitudin molestie malesuada. Lorem
      ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ante ipsum
      primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec
      velit neque, auctor sit amet aliquam vel, ullamcorper sit amet ligula.
      Curabitur aliquet quam id dui posuere blandit. Curabitur aliquet quam id
      dui posuere blandit. Curabitur aliquet quam id dui posuere blandit.
      Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere
      cubilia Curae; Donec velit neque, auctor sit amet aliquam vel, ullamcorper
      sit amet ligula. Praesent sapien massa, convallis a pellentesque nec,
      egestas non nisi. Vestibulum ac diam sit amet quam vehicula elementum sed
      sit amet dui.
    </p>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin eget tortor
      risus. Curabitur non nulla sit amet nisl tempus convallis quis ac lectus.
      Vivamus suscipit tortor eget felis porttitor volutpat. Pellentesque in
      ipsum id orci porta dapibus. Cras ultricies ligula sed magna dictum porta.
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque in
      ipsum id orci porta dapibus. Vestibulum ante ipsum primis in faucibus orci
      luctus et ultrices posuere cubilia Curae; Donec velit neque, auctor sit
      amet aliquam vel, ullamcorper sit amet ligula. Praesent sapien massa,
      convallis a pellentesque nec, egestas non nisi.
    </p>
  </div>
);

export default App;

索引.tsx

import { render } from "react-dom";
import App from "./App";

render(<App />, document.getElementById("root"));

样式.css

.app {
  margin-top: 120px;
  font-family: sans-serif;
  text-align: center;
  min-height: 120vh;
}

.navbar-top {
  padding: 0;
  background: #dadada;
  border-bottom: 2px solid #ccc;
}

.nav-link {
  padding: 2px 20px;
}

.search-box {
  height: 35px;
}

::-moz-focus-inner {
  border: 0;
}

::-webkit-scrollbar {
  display: none;
}

html,
body {
  margin: 0;
  padding: 0;
  background: #f9f9f9;
}

*,
:after,
:before {
  -ms-overflow-style: none;
  scrollbar-width: none;
  box-sizing: border-box;
}


推荐阅读