【问题标题】:How to set activeClassName for wrapper element of Link or IndexLink in react-router?如何在 react-router 中为 Link 或 IndexLink 的包装元素设置 activeClassName?
【发布时间】:2016-05-05 08:05:29
【问题描述】:

我是 ReactJS 世界的新手,想知道如何将活动类名传递给 <li> 元素而不是 <a>(Link) 元素。

现在我有这种代码。单击时锚类会发生变化。

<li><IndexLink to='/' activeclassName='active'>A</IndexLink></li>
<li><Link to='/b' activeclassName='active'>B</Link></li>
<li><Link to='/c' activeclassName='active'>C</Link></li>

但我想得到类似的东西:

<li activeclassName='active'><IndexLink to='/'>A</IndexLink></li>
<li activeclassName='active'><Link to='/b'>B</Link></li>
<li activeclassName='active'><Link to='/c'>C</Link></li>

提前致谢

【问题讨论】:

标签: javascript reactjs react-router redux


【解决方案1】:

我不知道原因,但对我来说 &lt;NavLink activeClassName="active" to="/events"&gt;&lt;li&gt;Events&lt;/li&gt;&lt;/NavLink&gt; 根本不起作用。

经过大量谷歌搜索,我在 `react-router-dom 提供的 useLocation() 属性的帮助下找到了解决方法。

import React from 'react';
import { useLocation } from 'react-router-dom';

// Active the Link on two URLs

export default () => {
    
    // extract pathname from location
    const { pathname } = useLocation();

    return (
        <li className='Navigation__list-item'> 
            <NavLink 
                to="/events" 
                className={pathname === "/events" ? "active" : ""} >
                Events 
            </NavLink> 
        </li>
    );
};

【讨论】:

    【解决方案2】:

    我正在使用 React Router v4.2,我无法从包装组件中获取对路由器对象的引用,因为上下文不可用。

    这不起作用:

    const { router } = this.context
    

    我喜欢@mpen 的answer,但我使用的是嵌套路由,我不想更改定义路由组件的文件。

    我所做的是将 location.pathname 与:

    const NavItem = withRouter(props => {
      const { to, children, location } = props;
      return (
        <li className={location.pathname == to ? "active" : null}>
          <Link to={to}>{children}</Link>
        </li>
      );
    });
    

    【讨论】:

      【解决方案3】:

      使用 React Router v4,我只是通过在 NavLink 组件中包含 &lt;li&gt; 标记来使其工作。使用 &lt;li&gt; 标签包裹链接的解决方案导致 HOME &lt;li&gt; 标签始终具有 active 类。

      import React from 'react'
      import { NavLink } from 'react-router-dom';
      
      class Header extends React.Component {
      
        render() {
          return (
            <div>
              <header>
      
                <nav>
                  <ul>
                    <NavLink activeClassName={"active"} exact={true} to="/"><li>Home</li></NavLink>
                    <NavLink activeClassName={"active"} to="/about"><li>About</li></NavLink>
                    <NavLink activeClassName={"active"} to="/courses"><li>Courses</li></NavLink>
                  </ul>
                </nav>
      
              </header>
            </div>
          )
        }
      }
      
      export default Header
      

      我相应地调整了lia CSS 选择器。

      【讨论】:

        【解决方案4】:

        我没有使用&lt;Link /&gt;,而是使用&lt;NavLink /&gt;,它也可以。

        import React, { Component } from 'react';
        import { NavLink } from 'react-router-dom';
        
        //.....
        
        export default class AppNav extends Component {
        
            render (){
                return (
                        <header>
                            <ul className="main-nav">
                                <li><NavLink activeClassName={"active"} exact={true} to="/">Home</NavLink></li>
                                <li><NavLink activeClassName={"active"} to="/about">About</NavLink></li>
                                <li><NavLink activeClassName={"active"} to="/courses">Courses</NavLink></li>
                            </ul>
                        </header>
                );
            }
        }
        

        【讨论】:

        • 这解决了我的问题。我想知道它们之间有什么区别使它起作用?
        • 为我工作,不需要任何解决方法,应该将其标记为最佳答案。
        • 是否设置了父&lt;li&gt;元素的类?对我来说,它只是设置从&lt;NavLink&gt; 创建的&lt;a&gt; 类。
        • 这不是问题。他询问了父类。
        • OP 想要将类添加到 Link 的父元素,而不是 Link 本身。
        【解决方案5】:

        其他答案似乎在 React Router v4 中不起作用。你可以这样做:

        import React, {PropTypes} from 'react'
        import {Route, Link} from 'react-router-dom'
        import styles from './styles.less';
        
        export default function NavItem({children, to, exact}) {
            return (
                <Route path={to} exact={exact} children={({match}) => (
                    <li className={match ? styles.activeRoute : null}>
                        <Link to={to}>{children}</Link>
                    </li>
                )}/>
            )
        }
        
        NavItem.propTypes = {
            to: PropTypes.string.isRequired,
            exact: PropTypes.bool,
            children: PropTypes.node.isRequired,
        };
        

        【讨论】:

        • 谢谢你。我会将...props 添加到参数中,并在&lt;Link to={to} {...props}&gt;{children}&lt;/Link&gt; 中使用它以更灵活。
        • 我不会使用三元运算符,而是使用 &lt;li className={match &amp;&amp; styles.activeRoute}&gt; 更简洁。
        • @Sag1v 我不再喜欢使用那种语法了。当它评估为0 时,我得到了一点,我的 UI 中有一个杂散的 0。如果您不小心,可能会产生更严重的错误。
        • @mpen 我知道你的意思,虽然在这种情况下0 会产生相同的效果,不是吗?
        • 更新了 jsfiddle 以获得@mpen 上面给出的答案:jsfiddle.net/69z2wepo/99537
        【解决方案6】:

        使用 react 15.1.0、react-router 2.5.0 和 bootstrap 3.3(这不太重要),我开发了这个解决方案来激活链接:

        npm install --save classnames

        npm install --save lodash

        组件:

        import React from 'react';
        import { Link, IndexLink } from 'react-router';
        import _ from 'lodash';
        import classnames from 'classnames';
        
        class NavItem extends React.Component {
          constructor(props) {
            super(props);
        
            // The default state
            this.state = {
              isActive: false,
              unregisterRouteListener: false
            };
        
            // Binding for functions
            this.locationHasChanged = this.locationHasChanged.bind(this);
          }
        
          componentDidMount() {
            // Check if component is active on mount and add listener on route change
            this.setState({
              isActive: this.context.router.isActive(this.props.to, true),
              unregisterRouteListener: this.context.router.listen(this.locationHasChanged)
            });
          }
        
          componentWillUnmount() {
            if (this.state.unregisterRouteListener) {
              // Remove the listener
              this.state.unregisterRouteListener();
            }
        
            // Reset the state
            this.setState({
              isActive: false,
              unregisterRouteListener: false
            });
          }
        
          // Update the state of the component, based on the router path
          locationHasChanged() {
            this.setState({
              isActive: this.context.router.isActive(this.props.to, true)
            });
          }
        
          render () {
            let { index } = this.props;
            let LinkComponent = index ? Link : IndexLink;
            let newProps = _.omit(this.props, 'router');
        
            return (
              <li className={classnames('', this.state.isActive ? 'active' : '' )}>
                <LinkComponent {...newProps}>
                  {this.props.children}
                </LinkComponent>
              </li>
            );
          }
        }
        
        NavItem.contextTypes = {
          router: React.PropTypes.object
        };
        
        export default NavItem;
        

        用法:

        <NavItem to="/list">List</NavItem>
        

        我是 React 的初学者,因此上述解决方案肯定需要改进,并且可能包含方法错误。但是,它也可能包含有用的信息或感兴趣的人的起点。

        非常欢迎任何反馈或建议。谢谢! :)

        【讨论】:

          【解决方案7】:

          试试react-router-active-component

          由于 react 或 typescript 版本之间的不兼容(这绝对不是一个成熟的生态系统),我无法获得任何以前的答案来轻松工作,但是这个组件成功了,并且可以应用于除 @ 之外的其他元素987654322@如果需要:

          import activeComponent from 'react-router-active-component'
          let NavItem = activeComponent('li');
          ...
          <NavItem to='/' onlyActiveOnIndex>Home</NavItem>
          <NavItem to='/generate-keywords'>Generate keywords</NavItem>
          

          【讨论】:

            【解决方案8】:

            您需要将您的&lt;li&gt; 封装为路由器感知组件:

            import { Link, IndexLink } from 'react-router'
            
            class NavItem extends React.Component {
              render () {
                const { router } = this.context
                const { index, onlyActiveOnIndex, to, children, ...props } = this.props
            
                const isActive = router.isActive(to, onlyActiveOnIndex)
                const LinkComponent = index ? Link : IndexLink
            
                return (
                  <li className={isActive ? 'active' : ''}>
                    <LinkComponent {...props}>{children}</LinkComponent>
                  </li>
                )
              }
            }
            

            用法:

            <ul>
              <NavItem to='/' index={true}>Home</NavItem>
              <NavItem to='/a'>A</NavItem>
            </ul>
            

            我从 react-router-bootstrap 模块 https://github.com/react-bootstrap/react-router-bootstrap/blob/master/src/LinkContainer.js 中获得灵感。我没有测试它,所以让我知道它是怎么回事。

            【讨论】:

            • 根据您的设置,您可能需要NavLi.contextTypes = { router: React.PropTypes.object }; export default NavLi;
            • 您可能需要确保您的组件获取上下文,例如router: PropTypes.object.isRequired
            • 不是通过上下文获取router,而是使用react-router包中的withRouter HOC通过props获取路由器。这也将在页面更改时更新链接的活动状态,否则 React 无法知道 isActive 是否已更改。
            • withRouter(...) 对我不起作用。 this.context.router 仍未定义 :(
            【解决方案9】:
            {/* Make sure that `location` is injected into this component */}
            <ul className="nav navbar-nav">
              <li className={location.pathname === '/' && 'active'}>
                <Link to='/'>
                  Home page
                </Link>
              </li>
              <li className={location.pathname.startsWith('/about') && 'active'}>
                <Link to='/about'>
                  About us
                </Link>
              </li>
            </ul>
            

            【讨论】:

            • 最简单的答案。
            【解决方案10】:
            /**
             * A navigation component
             */
            import React, { Component } from 'react'
            import { Link, IndexLink, withRouter } from 'react-router'
            
            import styles from './styles.scss'
            
            class NavItem extends Component {
              render () {
                const { router } = this.props
                const { index, to, children, ...props } = this.props
            
                let isActive
                if( router.isActive('/',true) && index ) isActive = true
                else  isActive = router.isActive(to)
                const LinkComponent = index ?  IndexLink : Link
            
                return (
                  <li className={isActive ? 'active' : ''}>
                    <LinkComponent to={to} {...props}>{children}</LinkComponent>
                  </li>
                )
              }
            }
            
            NavItem = withRouter(NavItem)
            
            export default NavItem
            

            用法:

            <ul className="nav nav-tabs"> 
              <NavItem to='/home' index={true} >Home</NavItem>
              <NavItem to='/about'>About</NavItem>
            </ul>
            

            【讨论】:

            • 虽然乍一看与 Marc 的答案相似,但这个答案对我来说效果更好。 withRouter 似乎是当前版本访问路由器的方式。
            • 这对我有用,但因为我使用的是 IndexLink,所以我做了一个更改: else isActive = router.isActive(to, true) 。我必须将 true 添加到 IsActive 函数,否则 isActive 总是为 '/' 返回 true。
            • 没用:router 对我来说是未定义的,在 this.props 中找不到 :-(
            【解决方案11】:

            很好的答案。

            只需更改以下内容即可使其正常工作...

            LinkComponent = index ? IndexLink : Link //If its true you want an IndexLink 
            
            //Also link needs to be...
            <NavItem to="/" onlyActiveOnIndex index={true}>Home</NavItem>
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-08-14
              • 2022-01-23
              • 2017-05-16
              • 2019-01-21
              • 1970-01-01
              • 2021-10-20
              • 2020-02-29
              • 2021-12-01
              相关资源
              最近更新 更多