【问题标题】:React scroll nav using useRef使用 useRef 反应滚动导航
【发布时间】:2020-07-30 09:13:24
【问题描述】:

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

我的标准如下:

  • 没有外部依赖
  • 必须在地址栏中包含 url(以允许直接链接到特定部分)
  • 不得乱七八糟(即将网址注入地址栏)
  • 必须尽可能简单

我希望这不是要求太多。

您可以玩一下我的 CodeSandbox Here。叉子表示赞赏!

【问题讨论】:

  • 好的。所以。我发现的第一个问题是 navlink 不能同时运行和运行 onClick。变通方法 1. 添加一个带有 onclick 的子组件, 2. 在 onclick 中处理所有 Navlink 事情(似乎太多了)。第二个问题是在功能组件中使用 ref。我现在正在调查。我认为有一个钩子。当我找到它时,我会发布一个答案和一个叉子。
  • 好的。您正在使用 ref 挂钩。但是有一个范围问题。在标题级别使用它对您在其他级别几乎没有影响。让我再玩一下。我想我已经差不多了。
  • 我现在必须停下来。 codesandbox.io/s/vigorous-microservice-3bqml?file=/src/App.tsx 应该是 onclick 工作的链接。您必须使用 ref 转发来获得所需的 ref。 reactjs.org/docs/forwarding-refs.html

标签: javascript reactjs typescript react-router


【解决方案1】:

您可以使用forwardRef HOC 包装每个部分。为每个部分创建并设置一个ref,并将引用传递给标题组件,以便它可以在它们上调用scrollIntoView 函数。

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

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

  useEffect(() => {
    console.log("location", location.pathname);
    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 => {
    console.log("Triggered.");
    ref.current.scrollIntoView({ behavior: "smooth" });
  };

  return (
    <>
      <NavLink to="/hero" activeClassName="selected">
        Hero
      </NavLink>
      <NavLink to="/about" activeClassName="selected">
        About
      </NavLink>
      <NavLink to="/contact" activeClassName="selected">
        Contact
      </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>
  );
}

【讨论】:

  • 谢谢!这确实有效,但是,它与标准不完全匹配。你知道如何调整代码,所以如果我在地址栏中输入/contact,它会向下滚动到联系人部分?
  • @Julian 添加了位置更改时触发滚动视图的效果。现在不需要 onclick。
  • 太棒了!完美的!太感谢了!您已经回答了我的问题并解决了我的问题!
  • @Julian 不幸的是我不精通打字稿。一个快速的谷歌搜索产生了这个:medium.com/@martin_hotell/… 有了它,我能够删除除标题之外的所有组件中的警告/错误。
  • @Julian 可以做到,因为它们真的只需要在一些共同祖先中定义。在演示中,App 恰好是最近的(也是唯一的)共同祖先。 IMO 在包含路由器/路由的组件中定义它们是有意义的,因为 该组件 可能拥有需要滚动到的路由或元素的最佳图片。
猜你喜欢
  • 2020-07-31
  • 2021-06-14
  • 1970-01-01
  • 2023-02-23
  • 1970-01-01
  • 1970-01-01
  • 2021-01-20
  • 1970-01-01
  • 2022-06-23
相关资源
最近更新 更多