如何在顶部导航栏部分下方添加粘性导航栏? ReactJS

时间:2021-03-15 19:52:16

标签: javascript reactjs material-ui

使用 ReactJS,我试图以同样的方式制作第二个(较小的)导航栏 Airtable has done on their product page。我的第一个导航栏位于顶部,滚动后从透明变暗。当我希望它位于标题背景图像的正下方时,第二个栏(在屏幕截图中为紫色以便于查看)目前位于第一个导航栏的后面。

第一个(主)导航栏 - “Header.js”

import React, { useEffect, useState } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { AppBar, IconButton, Toolbar, Collapse } from '@material-ui/core';
import SortIcon from '@material-ui/icons/Sort';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import { Link as Scroll } from 'react-scroll';
import ScrollToColor from './ColorChangeOnScroll';

const useStyles = makeStyles((theme) => ({
    root: {
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        height: '100vh',
        fontFamily: 'Nunito',
    },
    appbar: {
        background: 'none',
    },
    appbarTitle:{
        flexGrow: '1',
    },
    appbarWrapper:{
        width: '80%',
        margin: '0 auto',
    },
    icon: {
        color: '#fff',
        fontSize: '2rem',
    },
    colorText: {
        color: '#34cbc2',
    },
    container: {
        textAlign: 'center',
    },
    title: {
        color: '#fff',
        fontSize: '4rem',
    },
    goDown: {
        color: '#34cbc2',
        fontSize: '4rem',
    },
}));

export default function Header() {
    const classes = useStyles();
    const [checked, setChecked] = useState(false);
    useEffect(() => {
        setChecked(true);
    }, []);

    return (
        <section>
        <div className={classes.root} id="header">
            <ScrollToColor>
            <AppBar className={classes.appbar} elevation={0}>
                <Toolbar className={classes.appbarWrapper}>
                    <h1 className={classes.appbarTitle}>
                        Logo <span className={classes.colorText}>Colored</span>
                        </h1>
                    <IconButton>
                        <SortIcon className={classes.icon} />
                    </IconButton>
                </Toolbar>
            </AppBar>
            </ScrollToColor>

            <Collapse
            in={checked}
            {...(checked ? { timeout: 1000 } : {})}
            collapsedHeight={50}>
                <div className={classes.container}>
                    <h1 className={classes.title}>
                        Main header <br />
                        at <span className={classes.colorText}>title.</span>
                    </h1>
                    <Scroll to="info-card" smooth={true}>
                    <IconButton>
                      <ExpandMoreIcon className={classes.goDown} />
                    </IconButton>
                    </Scroll>
                </div>
            </Collapse>
        </div>
        </section>
    );
}

第二个导航栏 - “StickyHeader.js”

import React, { useEffect, useState } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { AppBar, IconButton, Toolbar, Collapse } from '@material-ui/core';
import SortIcon from '@material-ui/icons/Sort';

const useStyles = makeStyles((theme) => ({
    root: {
        top: '1000px',
        display: 'flex',
        position: 'sticky',
        justifyContent: 'center',
        alignItems: 'center',
        fontFamily: 'Nunito',
    },
    appbar: {
        background: 'purple',
    },
    list: {
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
    },
}));

export default function Header() {
    const classes = useStyles();
    const [checked, setChecked] = useState(false);
    useEffect(() => {
        setChecked(true);
    }, []);

    return (
        <section>
        <div className={classes.root} style={{ top: "72px" }} id="stickyheader">
            <AppBar className={classes.appbar} elevation={4}>
                <Toolbar className={classes.appbarWrapper}>
                    <ul className={classes.list} style={{ listStyleType: "none" }}>
                        <li>
                            <a href="#product" data-id="product" data-is-active="true">Database</a>
                        </li>
                    </ul>
                </Toolbar>
            </AppBar>
        </div>
        </section>
    );
}

登陆页面片段

export default function Landing() {
  const classes = useStyles();

  return (
      <div className={classes.root}>
          <CssBaseline />
          <Header />
          <StickyHeader />
          <InfoCards />

      </div>
  );
}

尝试调整:

  • 将每个组件分成各自的文件以充当“部分”,这样一个组件将位于另一个组件之上
  • 使用 margin 调整 marginTop 中的 useStylesposition: relative
  • 同上 position: sticky
  • style={{ top: "##px" }} 添加到导航栏的 div 以查看是否将其向下推

图片 顶部第 1 个后面的第 2 个导航栏 2nd navbar behind 1st at top

第一个导航栏后面的第二个导航栏,滚动 2nd navbar behind 1st, scrolled

所需结果的 Photoshop 视图(其中第二个导航栏是粘性的,滚动过去时“加入”第一个导航栏) Photoshopped view of the desired outcome

我不确定我是否在这些导航栏的样式中遗漏了一些简单的东西,或者这是否需要更复杂的东西。任何建议提前表示赞赏。

注意 徽标和标题标题是第一个导航栏的一部分。第二个(紫色)导航栏有一个非常小的“数据库”可点击文本,在前几个屏幕截图中很难看到,就在“彩色徽标”的顶部。

更新 MB_ 的回答的结果截图 enter image description here

1 个答案:

答案 0 :(得分:1)

编辑

这是我找到的唯一解决方案...

附注:

1/ 使用 position: "fixed" 而不是 position: "sticky"

2/ 还有其他修改要做...(添加滚动监听器,...)

Header.js

import React, { useEffect, useState } from "react";
import { makeStyles } from "@material-ui/core/styles";
import { AppBar, IconButton, Toolbar, Collapse } from "@material-ui/core";
import SortIcon from "@material-ui/icons/Sort";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
import { Link as Scroll } from "react-scroll";

const useStyles = makeStyles(theme => ({
  root: {
    fontFamily: "Nunito"
  },
  appbar: {
    position: "fixed",
    zIndex: "9999",
    background: "black"
  },
  appbarTitle: {
    flexGrow: "1"
  },
  appbarWrapper: {
    width: "80%",
    margin: "0 auto"
  },
  icon: {
    color: "#fff",
    fontSize: "2rem"
  },
  colorText: {
    color: "#34cbc2"
  },
  container: {
    textAlign: "center",
    height: "100vh",
    marginTop: "80px",
    display: "flex",
    flexDirection: "column",
    justifyContent: "center",
    alignItems: "center"
  },
  title: {
    color: "#333",
    fontSize: "4rem"
  },
  goDown: {
    color: "#34cbc2",
    fontSize: "4rem"
  }
}));

export default function Header() {
  const classes = useStyles();
  const [checked, setChecked] = useState(false);
  useEffect(() => {
    setChecked(true);
  }, []);

  return (
    <div className={classes.root} id="header">
      <AppBar className={classes.appbar} elevation={0}>
        <Toolbar className={classes.appbarWrapper}>
          <h1 className={classes.appbarTitle}>
            Logo <span className={classes.colorText}>Colored</span>
          </h1>
          <IconButton>
            <SortIcon className={classes.icon} />
          </IconButton>
        </Toolbar>
      </AppBar>

      <Collapse
        in={checked}
        {...(checked ? { timeout: 1000 } : {})}
        collapsedHeight={50}
      >
        <div id="mainheader" className={classes.container}>
          <h1 className={classes.title}>
            Main header <br />
            at <span className={classes.colorText}>title.</span>
          </h1>
          <Scroll to="info-card" smooth={true}>
            <IconButton>
              <ExpandMoreIcon className={classes.goDown} />
            </IconButton>
          </Scroll>
        </div>
      </Collapse>
    </div>
  );
}

StickyHeader.js

import React, { useEffect, useState } from "react";
import { makeStyles } from "@material-ui/core/styles";
import { AppBar, IconButton, Toolbar, Collapse } from "@material-ui/core";

const useStyles = makeStyles(theme => ({
  root: {
    fontFamily: "Nunito"
  },
  appbar: {
    background: "purple"
  },
  list: {
    display: "flex",
    justifyContent: "center",
    alignItems: "center"
  }
}));

export default function StickyHeader() {
  const classes = useStyles();
  const [checked, setChecked] = useState(false);
  const [scrollY, setScrollY] = useState({ position: "relative" });

  useEffect(() => {
    window.addEventListener("scroll", () => {
      const heightVh = document.querySelector("#mainheader").offsetHeight / 100;

      if (window.scrollY > heightVh * 100) {
        setScrollY({ position: "fixed", top: "80px" });
      } else {
        setScrollY({ position: "relative" });
      }
    });
    return () => {
      window.removeEventListener("scroll");
    };
  }, [scroll]);

  useEffect(() => {
    setChecked(true);
  }, []);

  return (
    <>
      {console.log(scrollY)}
      <div className={classes.root} id="stickyheader">
        <AppBar className={classes.appbar} style={scrollY} elevation={4}>
          <Toolbar className={classes.appbarWrapper}>
            <ul className={classes.list} style={{ listStyleType: "none" }}>
              <li>
                <a href="#product" data-id="product" data-is-active="true">
                  Database
                </a>
              </li>
            </ul>
          </Toolbar>
        </AppBar>
      </div>
    </>
  );
}

演示:stackblitz