使用useRef的滚动导航

问题描述 投票:1回答:1

我正在尝试制作一个单页应用,在其中单击链接,它向下滚动到与菜单项相对应的部分。我花了几天时间研究适合我的标准的修复程序,但不幸的是,我的运气很少。

我的标准如下:

  • 无外部依赖项
  • 必须在地址栏中输入网址(以允许直接链接到特定部分)
  • 一定不要太过粗暴(即将URL注入地址栏中)
  • 必须尽可能简单

我希望不要要求太多。

您可以玩我的CodeSandbox Here。感谢叉子!

javascript reactjs typescript react-router
1个回答
1
投票

您可以用forwardRef HOC包装每个部分。为每个部分创建并设置一个ref,然后将引用传递给标头组件,以便它可以在其上调用scrollIntoView函数。如前所述,NavLink不能使用onClick道具,但是您可以将内部文本包装在span或div中,然后在其中附加onClick处理程序。

edit添加了一个效果来查看位置并触发滚动。

const Header = ({ refs }) => {
  const location = useLocation();

  useEffect(() => {
    switch (location.pathname) {
      case "/about":
        scrollSmoothHandler(refs.aboutRef)();
        break;
      case "/contact":
        scrollSmoothHandler(refs.contactRef)();
        break;
      case "/hero":
        scrollSmoothHandler(refs.heroRef)();
        break;
      default:
      // ignore
    }
  }, [location, refs]);

  const scrollSmoothHandler = ref => () => {
    ref.current.scrollIntoView({ behavior: "smooth" });
  };

  return (
    <>
      <NavLink to="/hero" activeClassName="selected">
        <div onClick={scrollSmoothHandler(refs.heroRef)}>
        Hero
        </div>
      </NavLink>
      <NavLink to="/about" activeClassName="selected">
      <div onClick={scrollSmoothHandler(refs.aboutRef)}>
        About
        </div>
      </NavLink>
      <NavLink
        to="/contact"
        activeClassName="selected"
      >
        <div onClick={scrollSmoothHandler(refs.contactRef)}>
        Contact
        </div>
      </NavLink>
    </>
  );
}

const Hero = forwardRef((props, ref) => {
  return (
    <section ref={ref} >
      <h1>Hero Section</h1>
    </section>
  );
});

const About = forwardRef((props, ref) => {
  return (
    <section ref={ref}>
      <h1>About Section</h1>
    </section>
  );
});

const Contact = forwardRef((props, ref) => {
  return (
    <section ref={ref}>
      <h1>Contact Section</h1>
    </section>
  );
});

function App() {
  const heroRef = useRef(null);
  const aboutRef = useRef(null);
  const contactRef = useRef(null);

  return (
    <div className="App">
      <HashRouter>
        <Header refs={{ aboutRef, contactRef, heroRef}} />
        <Hero ref={heroRef}/>
        <About ref={aboutRef} />
        <Contact ref={contactRef} />
      </HashRouter>
    </div>
  );
}

Edit forwardRef and scrollIntoView

© www.soinside.com 2019 - 2024. All rights reserved.