【问题标题】:Dynamically adding active class to multi level sidebar menu in REACT JS在 REACT JS 中将活动类动态添加到多级侧边栏菜单
【发布时间】:2019-06-01 04:32:23
【问题描述】:

我目前正在 REACT 中创建一个多级侧边栏菜单,并且我想在当前路由处于活动状态时动态地将活动类添加到父 <li>

下面的代码是我如何为单个菜单做的。

<Route
  path={this.props.to}
  exact={this.props.activeOnlyWhenExact}
  children={({ match }) => (
    <li className={match ? "active" : ""}>
      <Link to={this.props.to} activeClassName="active">
        <span className="sidebar-mini-icon">
          <i className={this.props.icon}></i></span>
          {this.props.label}
      </Link>
    </li>
  )}
/>

现在我想知道如何使用多级菜单来做到这一点。我的菜单是这样的;

如您所见,只有菜单具有活动类。这是我的多级菜单代码:

<Route
  path={this.props.to}
  exact={this.props.activeOnlyWhenExact}
  children={({ match }) => (
  <li>
    <a data-toggle="collapse" href="#Collapse">
      <span className="sidebar-mini-icon">
        <i className={this.props.icon}></i>
      </span>
      <span className="sidebar-normal">
        {this.props.name}
        <b className="caret"></b>
      </span>
    </a>
    <div class="collapse" id="Collapse">
       <ul className="nav">
         {this.props.children}
       </ul>
    </div>
  </li>
  )}
/>

我正在使用 React 路由器。任何帮助将不胜感激。谢谢。

【问题讨论】:

  • 我也在寻找类似的答案。请帮助某人。
  • @Sonson Ixon,你的问题得到解答了吗?

标签: javascript reactjs react-router


【解决方案1】:

我的第一反应是将className={match ? "active" : ""} 添加到父级li,但既然你在问它,我假设你已经尝试过了。

您可以在孩子们的道具中四处挖掘,看看他们中是否有人拥有match 道具(或任何其他表明他们处于活动状态的道具)。以下函数可以从孩子们那里找到一个match 道具。

const childMatch = children => {
  if (!children) { return false }
  if (Array.isArray(children)) {
    return children.reduce(
      (acc, child) => acc || Boolean(child.props.match),
      false
    )
  }
  return Boolean(children.props.match)
}

你可以像className={childMatch(this.props.children) ? "active" : ""}一样使用它。

如果您要寻找的道具在儿童树的更深处,您当然可以更深入地挖掘。您可以通过child.props.children 找到孙子。

【讨论】:

  • 这不起作用。不过谢谢你的回复。赞赏。
【解决方案2】:

您可以使用React router's nav link

<NavLink to="/faq" activeClassName="selected">
  FAQs
</NavLink>

【讨论】:

  • 那将是单个菜单,我们正在寻找将类添加到父菜单
  • 不,它没有依赖关系。如果您正在前往它将添加 activeClassName。它没有父子依赖。
【解决方案3】:

选项 1

您可以使用useLocation 挂钩。

使用useMemo 挂钩,您可以在位置更改时运行函数。这样,您可以在每次位置更改时将该类添加到活动父级。

但您需要确保 useLocation 调用不在将路由器放入 DOM 的同一组件中。

所以在根索引文件或其他一些组件中,你可以有这样的东西

import { useLocation, useEffect } from "react-router-dom";

const Item = () => {
  const location = useLocation();

  // Select the nav item with the active class, and add the extra class to its parent
  useMemo(() => document.querySelector(activeClassName)?.parentElement?.classList.add(activeParentClassName), [location])
  
  return (...);
}

选项 2

这是基于这样的假设,即分组的路线具有相同的起始路线,例如 /a/b/ca/b/e

多级菜单项应该像这样呈现。

组的标签应该有自己的Route,它不应该是精确的,并且应该有一个路径,使它成为实际菜单链接的父目录

<li>
  <Route
    path="/a"
    children={({ match }) => (
      <a data-toggle="collapse" href="#Collapse" className={match ? 'active' : ''}>
          ...
      </a>
    )}
  />

然后菜单中的实际链接项应该是准确的,并且具有使其成为第一个键的子目录的路径

<ul>
  <Route
    exact
    path="/a/b"
    children={({ match }) => (
      <li className={match ? "active" : ""}>
        <Link to={this.props.to} activeClassName="active">
          {/* ... */}
        </Link>
      </li>
    )}
  />
  {/* other routes */}
</ul>

【讨论】:

  • 这里不需要使用 useEffect 或 Dom 选择器,找出组和链接是否应该处于活动状态(useMemo 最多是同步的)并从中派生正确的类(作为prop 如果需要)在 JSX 中从树中的相同或更高级别。访问 DOM 用于极少数用例,在反应树中写入 DOM 总是不正确的。
【解决方案4】:

解决方案取决于您的路线配置。如果您使用非精确路由,NavLink 的解决方案将是最适用的。

例子:

routes.jsx

<Route path="/parent/child-a">
  <ChildA />
</Route>
<Route path="/parent/child-b">
  <ChildB />
</Route>
<Route path="/parent">
  <Parent />
</Route>

使用上述结构,/parent/child-a 将匹配两个路由(/parent/parent/child-a),NavLink 上的 activeClassName 属性将应用于两个 HTML 元素。

上述结构的“挑战”是你要在所有三种情况下渲染&lt;Parent /&gt;

这可以通过使用嵌套/子路由来解决。

routes.jsx

<Route path="/parent">
  <NestedRoutes />
</Route>

nestedRoutes.jsx

<Route path="/parent/child-a" exact>
  <ChildA />
</Route>
<Route path="/parent/child-b" exact>
  <ChildB />
</Route>

使用上面更新的结构,/parent/child-a 将匹配顶级路由(并因此将activeClassName 添加到您的 HTML 元素中)并且 匹配子路由并添加activeClassName 也有。

请注意,如果您需要 /parent 也可以用作路由,则需要按如下方式更新嵌套路由:

nestedRoutes.jsx

<Route path="/parent" exact>
  <Parent />
</Route>

根据我的经验,如果您发现自己通过 JavaScript 或 useLocation 手动处理这些情况,您可能需要重新访问您的路由配置。 react-router 是一个简洁的优秀库,可能会开箱即用地处理您的案例。

【讨论】:

    【解决方案5】:

    这是一个很好的问题!

    如果我理解正确,希望在当前路由匹配的情况下将活动类动态添加到 li 元素。

    为此,让我们创建一个名为 NavListItem 的新组件。 NavListItem 将检查当前路由是否与其to 属性匹配。如果是这样,它将呈现 activeClassName。这与 react-router-doms NavLink 组件没什么不同。除了我们将呈现li 而不是链接。

    NavListItem.js

    import React from 'react';
    import { useLocation, matchPath } from 'react-router-dom';
    
    export const NavListItem = ({
      path,
      exact,
      sensitive,
      strict,
      activeClassName = 'active',
      className,
      children,
      ...otherProps
    }) => {
      const location = useLocation();
    
      const match = matchPath(location.pathName, {
        path: path,
        exact: exact,
        sensitive: sensitive,
        strict: strict,
      });
    
      const isActive = Boolean(match);
    
      const className = isActive ? [activeClassName, className].join(' ') : className;
    
      const props = {
        className: className,
        ...otherProps,
      };
    
      return <li {...props}>{children}</li>;
    };
    

    这是您的示例代码的用法。

    <NavListItem path={this.props.to} exact={this.props.activeOnlyWhenExact}>
      <a data-toggle="collapse" href="#Collapse">
        <span className="sidebar-mini-icon">
          <i className={this.props.icon}></i>
        </span>
        <span className="sidebar-normal">
          {this.props.name}
          <b className="caret"></b>
        </span>
      </a>
      <div class="collapse" id="Collapse">
        <ul className="nav">{this.props.children}</ul>
      </div>
    </NavListItem>
    

    【讨论】:

      【解决方案6】:

      根据您的问题。 我建议使用 React 路由器的导航链接

      <NavLink to="/<route-name>" activeClassName=<classname>>
        Title
      </NavLink>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-02-22
        • 1970-01-01
        • 2020-07-16
        • 1970-01-01
        • 2020-02-03
        • 1970-01-01
        • 1970-01-01
        • 2015-08-05
        相关资源
        最近更新 更多