【问题标题】:Active NavLink to parent element活动导航链接到父元素
【发布时间】:2018-06-15 14:36:59
【问题描述】:

我正在使用 React Router v4,并且在我的导航链接上,我想将 active className 启用到 NavLink 父元素,而不是 NavLink 本身。

有没有办法访问路径 (match),即使我不在 Switch 元素内?

或者我必须保持状态?因为我觉得它有点缺少路由器的想法。

这是我的示例,我想将active className 应用于li 元素而不是NavLink

const {
  HashRouter,
  Switch,
  Route,
  Link,
  NavLink,
} = ReactRouterDOM

const About = () => (
    <article>
        My name is Moshe and I'm learning React and React Router v4.
    </article>
);

const Page = () => (
    <Switch>
      <Route exact path='/'  render={() => <h1>Welcome!</h1>} />
      <Route path='/about' component={About}/>
    </Switch>
);

const Nav = () => (
    <nav>
        <ul>
            <li><NavLink exact to="/">Home</NavLink></li>
            <li><NavLink to="/about">About</NavLink></li>
        </ul>
    </nav>
);

class App extends React.Component {
    render() {
        return (
            <div>
                <Nav />
                <Page />
            </div>
        );
    }
}
ReactDOM.render((
    <HashRouter>
        <App />
    </HashRouter>),
    document.querySelector("#app"));

https://codepen.io/moshem/pen/ypzmQX

【问题讨论】:

标签: reactjs react-router


【解决方案1】:

这似乎并不容易实现。我使用了react router docs 中描述的withRouter HOC。它允许从位于Routess 外部的props 内部组件访问{ match, location, history }。在示例中,我包装了Nav 组件以获取location 及其pathname。下面是示例代码:

class Nav extends React.Component {
 getNavLinkClass = (path) => {
   return this.props.location.pathname === path ? 'active' : '';
 }
 render() {
  return (
    <nav>
      <ul>
        <li className={this.getNavLinkClass("/")}><NavLink exact to="/">Home</NavLink></li>
        <li className={this.getNavLinkClass("/about")}><NavLink to="/about">About</NavLink></li>
      </ul>
    </nav>
  )};
}
Nav = withRouter(Nav);

您可能必须在您的路线中处理params(如果有的话),以正确匹配。但是您仍然必须匹配NavLink 中的每条路径,这可能不是漂亮的代码。但想法是,当路线改变时,Nav 被重新渲染,正确的li 被突出显示。

这是codesandbox 上的一个工作示例。

【讨论】:

    【解决方案2】:

    可以通过Route组件实现

    <ul>
      <Route path="/about">
        {({ match }) => <li className={match ? 'active' : undefined}><Link to="/about">About</Link></li>
      </Route>
    </ul>
    

    参考:https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/Route.md#children-func

    【讨论】:

      【解决方案3】:

      如果您完全放弃NavLink 组件,您可以使用useHistory()react-router-dom 中的useLocation() 创建自己的组件来模拟NavLink 的“活动性”。

      仪表板.js

      const routeItems = [
        { route: '/route1', text: 'Route 1' },
        { route: '/route2', text: 'Route 2' },
      ];
      
      <Router>
        <NavBar routeItems={routeItems} />
      </Router>
      

      NavBar.js中,我们只需要检查当前活动的路线是否与上任何单个项目的路线相同

      NavBar.js

      import { useHistory, useLocation } from 'react-router-dom';
      
      const NavBar = (props) => {
        const { routeItems } = props;
        const history = useHistory();
        const location = useLocation();
      
        const navItems = routeItems.map((navItem) => {
          return (
            <div style={{
              backgroundColor: navItem.route === location.pathname ? '#ADD8E6' : '',
            }}
              onClick={() => {
                history.push(navItem.route);
              }}
            >
              {navItem.text}
            </div>
          );
        });
      
        return (navItems);
      };
      export default NavBar;
      

      【讨论】:

        【解决方案4】:

        我为我的情况找到了更简单的解决方案,我有嵌套项目,但我知道每个嵌套的基础

        例如,巢的基础是/customer,它包含这样的项目 /customer/list , /customer/roles ...

        所以确实在父NavLink 中的isActive 属性中添加了一些逻辑

        带有解释的代码:

        <NavLink
        to={item.route}
        activeClassName={classes.activeItem}
        onClick={e => handleItemClick(e, key)}
        isActive={(match, location) => {
                 // remove last part of path ( admin/customer/list becomes admin/customer for example )
                 const pathWithoutLastPart = location.pathname.slice(0, location.pathname.lastIndexOf("/"));
                      // if current parent is matched and doesn't contain childs activate it 
                      if (item.items.length === 0 && match) {
                        return true;
                      } 
                      // if sliced path matches parent path 
                      in case of customer item it becomes true ( admin/customer === admin/customer )
                      else if (pathWithoutLastPart === item.route) {
                        return true;
                      } 
                      // else inactive item
                      else {
                        return false;
                      }
                    }}
                  >
        ...
        </NavLink>
        

        现在父母和孩子一起活动

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-10-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多