如何使用 React 实现带哈希路由的 Scrollspy

How to achieve Scrollspy with hash routing using react

我正在使用react(Hooks),我做了很多事情,但是几天来我一直卡在一个地方。

我想创建一个 scrollspy 使用对路由的反应,当滚动新菜单处于活动状态时我想更改路由

[请参考这个link][1]这就是我想要实现的,这里他们使用哈希路由

我在做什么

  1. 我有一个侧边栏,其中有一些菜单。
  2. 我正在循环数据并显示侧边栏,工作正常。

我想要达到的目标

  1. 对于每个菜单我都有一些数据,我想显示
  2. 因此,当我滚动并且第一个菜单文本结束时,我想激活下一个菜单,但也要更改路径
  3. 比如有一些路由 --- /home、/profile、/status、/info。
  4. 因此,当我 **scrollspy ** 更改菜单时,我也想更改路线,因为我有来自 Api 的数据。
  5. 我无法在特定路径中显示数据,例如当我单击配置文件时我想在该页面中显示该数据,但无法传递该数据。

通过简单的点击路由就可以了,我很容易就能实现,但是这里我想实现别的东西,很难做到。

JSON数据

    [
    {
      menu: "HOME",
      path: "home",
      data:
        "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
    },
    {
      menu: "PROFILE",
      path: "profile",
      data:
        "The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from 'de Finibus Bonorum et Malorum' by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham."
    },
    {
      menu: "STATUS",
      path: "status",
      data:
        "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English."
    },
    {
      menu: "INFO",
      path: "info",
      data:
        "Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like). q"
    }
  ]

在上面的数据中,我有 数据,我想在滚动或点击时在每个相应的路径中显示。

点击后,我可以更改路由并呈现点击的页面。

我的代码

下面是我的菜单栏.js文件

<div className="menuBar">
  <Nav className="mr-auto ml-1">
    {data.map((li, ind) => (
      <li className="nav-item" key={li.path}>
        <NavLink
          className="nav-link"
          activeClassName="active"
          to={`${li.path}`}
          onClick={() => OnclickSidebar(li.menu, li.path)}
        >
          {li.menu}
        </NavLink>
      </li>
    ))}
  </Nav>
</div>

route.js 文件

 <Switch>
    <Route exact path="/" component={Home} />
    <Route exact path="/home" component={Home} />
    <Route path="/profile" component={Profile} />
    <Route path="/status" component={Status} />
    <Route path="/info" component={Info} />
    <Route path="/*" component={() => "Page not found"} />
  </Switch>

以上是我目前的情况,现在还没有任何前进的想法,所以在这里寻求一些想法。

PS : 请参考[This is what I exactly i want][1],这里使用了哈希路由。

编辑/更新

我有上述数据,并且我已经分享了 link 我正在努力实现的目标,我愿意就如何解决这个问题提出建议。 由于我对这部分完全陌生,不知道我应该如何开始实现这一目标。

分享更多信息

当我打开页面时,初始路线显示 [![检查此图像,它显示 public 路线][2]][2]

现在,当我在侧边栏上滚动时,概览变为活动状态并且概览路线显示 [![查看此图片][3]][3]

以上就是我要实现的

同样适用于所有侧边栏菜单,现在侧边栏也有一些子菜单,它们的工作方式完全相同,如果我能够用一个流程实现这个子菜单我可以自己做。 为此,我只需要一个良好的开端。

[我的代码沙箱link][4]

如何检查子菜单并在菜单处于活动状态时打开

其实我的数据有一些子菜单

    [
    {
        menu: 'HOME',
        path: 'home',
        data:
            "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
    },
    {
        menu: 'PROFILE',
        path: 'profile',
        data:
            "The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from 'de Finibus Bonorum et Malorum' by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.",
        Sub_menu: [ // some menus have submenus also
            {
                menu: 'Profile1',
                path: '/profile/profile1',
                data: 'Some data for the sub menu',
            },
            {
                menu: 'Profile2',
                path: '/profile/profile2',
                data: 'Some data for the sub menu 2',
            },
        ],
    },
    {
        menu: 'STATUS',
        path: 'status',
        data:
            "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
    },
    {
        menu: 'INFO',
        path: 'info',
        data:
            "Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like). q",
        Sub_menu: [
            {
                menu: 'info1',
                path: '/info/info1',
                data: 'Some data for the sub menu info',
            },
            {
                menu: 'info2',
                path: '/info/info2',
                data: 'Some data for the sub menu info2',
            },
        ],
    },
];

[![当有子菜单的菜单处于活动状态时][5]][5]

[![当子菜单处于活动状态时路线会照常更改][6]][6]

实施涉及三个方面:

  1. 导航栏
  2. 路由器
  3. 滚动间谍

NavBar 中: 这里需要一个第三方库,让我们安装它:

npm install react-router-hash-link

现在,实施它:

import {HashLink} from 'react-router-hash-link';

const NavBar = () => (
  <div className="menuBar">
    <div className="mr-auto ml-1">
      {data.map((item) => (
        <li className="nav-item" key={item.path}>
          <HashLink to={`#${item.path}`} smooth={true}>
            {item.menu}
          </HashLink>
        </li>
      ))}
    </div>
  </div>
);

这时候NavBar组件就大功告成了。让我们继续第二部分,路由器

您需要一个组件来呈现其上的所有数据:

<Route exact={true} path="/" component={Home} />

在示例 Home 组件中,我们需要一个组件来呈现每个部分:

const Section = ({ title, description, path }) => {
  const history = useHistory();

  useEffect(() => {
    const el = document.getElementById(path);
    const observer = new window.IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          history.push(`#${path}`);
          return;
        }
      },
      {
        root: null,
        threshold: 0.1 // set offset 0.1 means trigger if atleast 10% of element in viewport
      }
    );

    observer.observe(el);
  }, [path, history]);

  return (
    <div style={{ height: "500px" }}>
      <h3 id={path}>{title}</h3>
      <p>{description}</p>
    </div>
  );
};

最重要的魔法就在这里,在 useEffect 挂钩中,当前活动的部分已被观看。让我们一起使用 NavBarSection 组件:

const App = () => {
  return (
    <div>
      <div>
        <NavBar />
      </div>
      <div>
        {data.map((item) => (
          <Section
            title={item.menu}
            description={item.data}
            path={item.path}
            key={item.path}
          />
        ))}
      </div>
    </div>
  );
};

export default App;

此外,您可以在codesandbox上查看简单版本。