Javascript 如何在 react-router 中为 Link 或 IndexLink 的包装元素设置 activeClassName?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35053161/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 17:13:21  来源:igfitidea点击:

How to set activeClassName for wrapper element of Link or IndexLink in react-router?

javascriptreactjsreact-routerredux

提问by abekenza

I am new to the ReactJS world, and would like to know how can I pass active class name to the <li>element instead of <a>(Link)element.

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

Now I have this kind of code. The anchor class changes when clicked.

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

<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>

But I would like to get something similar to:

但我想得到类似的东西:

<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>

Thanks in advance

提前致谢

采纳答案by Marc Greenstock

You need to enclose your <li>as a router aware component:

您需要将您的<li>作为路由器感知组件附上:

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>
    )
  }
}

Usage:

用法:

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

I took inspration from the react-router-bootstrap module, https://github.com/react-bootstrap/react-router-bootstrap/blob/master/src/LinkContainer.js. I didn't test it though so let me know how it goes.

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

回答by mpen

The other answers don't seem to work in React Router v4. Here's how you can do it:

其他答案似乎在 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,
};

回答by bryanyu

/**
 * 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

Usage:

用法:

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

回答by kenberkeley

{/* 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>

回答by Dimang Chou

In stead of using <Link />, I use <NavLink />and It works as well.

<Link />我没有使用,而是使用<NavLink />和 它也能工作。

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>
        );
    }
}

回答by Matthew Berends

Great answer.

很好的答案。

Just change the following to get it working...

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

LinkComponent = index ? IndexLink : Link //If its true you want an IndexLink 

//Also link needs to be...
<NavItem to="/" onlyActiveOnIndex index={true}>Home</NavItem>

回答by Erwin Mayer

Try with react-router-active-component.

尝试使用react-router-active-component

I couldn't get any of the previous answers to easily work due to incompatibilities between react or typescript versions (this is definitely not a mature ecosystem), but this component did the trick, and can be applied to other elements than liif needed:

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

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

回答by Cristi Draghici

Using react 15.1.0, react-router 2.5.0 and bootstrap 3.3 (this is less important), I developed this solution for making the links active:

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

npm install --save classnames

npm install --save classnames

npm install --save lodash

npm install --save lodash

The component:

组件:

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;

Usage:

用法:

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

I am a beginner with React, so the above solution surely needs improvements and might contain approach errors. However, it might also contain useful information or a starting point to those interested.

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

Any feedback or suggestions are more than welcome. Thanks! :)

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

回答by Jernej Gori?ki

I'm using React Router v4.2 and I couldn't get the reference to the router object from the wrapping component, because the context is not available.

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

This did not work:

这不起作用:

const { router } = this.context

I like @mpen's answer, but I'm using nested routes and I don't want to change the file where I have the routing component defined.

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

What I did is compared the location.pathname with to :

我所做的是将 location.pathname 与 to 进行比较:

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

回答by Steve Breese

Using React Router v4, I only got it to work by including the <li>tags within the NavLink component. The solutions which have the <li>tags wrapping the links resulted in the HOME <li>tag always having the activeclass.

使用 React Router v4,我只是通过<li>在 NavLink 组件中包含标签来让它工作。具有<li>包装链接的标签的解决方案导致 HOME<li>标签始终具有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

I adjusted the liand aCSS selectors accordingly.

我相应地调整了liaCSS 选择器。