如何将活动类添加到 React Router 的链接?

Posted

技术标签:

【中文标题】如何将活动类添加到 React Router 的链接?【英文标题】:How do I add an active class to a Link from React Router? 【发布时间】:2016-03-28 20:38:23 【问题描述】:

我使用Link 创建了一个引导式侧边栏。这是我的代码的 sn-p:

<ul className="sidebar-menu">
  <li className="header">MAIN NAVIGATION</li>
  <li><Link to="dashboard"><i className="fa fa-dashboard"></i> <span>Dashboard</span></Link></li>
  <li><Link to="email_lists"><i className="fa fa-envelope-o"></i> <span>Email Lists</span></Link></li>
  <li><Link to="billing"><i className="fa fa-credit-card"></i> <span>Buy Verifications</span></Link></li>
</ul>

我想在包装元素&lt;li&gt; 上将活动路径的类设置为active。我看到还有其他解决方案可以展示如何做到这一点,例如Conditionally set active class on menu using react router current route,但是我认为这不是将包装器上的活动类设置为Link 的最佳方式。

我也找到了https://github.com/insin/react-router-active-component,但感觉没必要。

在 React Router 中,这是可能的还是我需要使用外部解决方案?

【问题讨论】:

【参考方案1】:

您现在可以在 Link 组件上添加 activeClassName 或设置 activeStyle

这些使您可以轻松地将样式添加到当前活动的链接。


以前,您可以使用以下逻辑创建一个自定义组件,该组件类似于链接的包装器。

在名为 nav_link.js 的文件中

import React from 'react';
import  Link  from 'react-router-dom';
import PropTypes from 'prop-types';

class NavLink extends React.Component 
    render() 
        var isActive = this.context.router.route.location.pathname === this.props.to;
        var className = isActive ? 'active' : '';

        return(
            <Link className=className ...this.props>
                this.props.children
            </Link>
        );
    


NavLink.contextTypes = 
    router: PropTypes.object
;

export default NavLink;

并在您的组件中使用它,如下所示:

...
import NavLink from "./nav_link";
.....

<nav>
    <ul className="nav nav-pills pull-right">
        <NavLink to="/">
            <i className="glyphicon glyphicon-home"></i> <span>Home</span>
        </NavLink>
        <NavLink to="about">
            <i className="glyphicon glyphicon-camera"></i> <span>About</span>
        </NavLink>
    </ul>
</nav>

【讨论】:

NavLink 组件中的内容类型应该是静态属性而不是实例属性。请更正。 为什么不使用react-router 公开的activeStyleactiveClassName。周围有一些documentation。 这似乎不再适用于 react-router v4.0.0,因为 router.isActive 不再存在。见:github.com/react-bootstrap/react-router-bootstrap/issues/186 使用 react-router 3.0.0 ,得到TypeError: Cannot read property 'location' of undefined 是的,它应该是公认的答案。它对我来说效果很好!但是,配置不仅仅是这些步骤。对我来说,它只是确保我的导航中的 组件都被这个包裹了。还有其他步骤使这项工作在宏伟的计划中发挥作用。稍后有空我会在这里分享。【参考方案2】:

用 ES6 更新答案:

import React,  Component  from 'react';
import  Link  from 'react-router'

class NavLink extends Component 
    render() 
        let isActive = this.context.router.isActive(this.props.to, true);
        let className = isActive ? "active" : "";

        return (
            <li className=className>
                <Link ...this.props/>
            </li>
        );
    


NavLink.contextTypes = 
    router: React.PropTypes.object
;

export default NavLink;

然后如上所述使用它。

【讨论】:

this.context.route 未定义我(较新版本?),您可以使用withRouter 函数在参数中传递路由器【参考方案3】:

我不喜欢创建自定义组件的想法,因为如果您有不同的包装元素,您将不得不创建另一个自定义组件等。而且,这只是矫枉过正。所以我只是用 css 和 activeClassName 做的:

<li className="link-wrapper">  <!-- add a class to the wrapper -->
  <Link to="something" activeClassName="active">Something</Link>
</li>

然后只需添加一些 css:

li.link-wrapper > a.active 
    display: block;
    width: 100%;
    height:100%;
    color: white;
    background-color: blue;

从技术上讲,这不会设置 li 的样式,但它会使锚填充 li 并设置它的样式。

【讨论】:

【参考方案4】:

这是我的方式,使用来自道具的位置。 我不知道,但 history.isActive 对我来说是未定义的

export default class Navbar extends React.Component 
render()
const  location  = this.props;

const homeClass = location.pathname === "/" ? "active" : "";
const aboutClass = location.pathname.match(/^\/about/) ? "active" : "";
const contactClass = location.pathname.match(/^\/contact/) ? "active" : "";


return (
<div>
      <ul className="nav navbar-nav navbar-right">
        <li className=homeClass><Link to="/">Home</Link></li>
        <li className=aboutClass><Link to="about" activeClassName="active">About</Link></li>
        <li className=contactClass><Link to="contact" activeClassName="active">Contact</Link></li>
      </ul>

</div>
    );

【讨论】:

&lt;li class=homeClass&gt; ... &lt;/li&gt; 更改 class=> 类名【参考方案5】:

您实际上可以复制 NavLink 内部的内容

const NavLink = ( 
  to,
  exact,
  children
 ) => 

  const navLink = (match) => 

    return (
      <li class=active: match>
        <Link to=to>
          children
        </Link>
      </li>
    )

  

  return (
    <Route
      path=typeof to === 'object' ? to.pathname : to
      exact=exact
      strict=false
      children=navLink
    />
  )

只需查看NavLink 源代码并删除不需要的部分;)

【讨论】:

【参考方案6】:

React-Router V4带有一个开箱即用的NavLink组件

要使用,只需将activeClassName 属性设置为您已适当样式的类,或直接将activeStyle 设置为您想要的样式。详情请见the docs。

<NavLink
  to="/hello"
  activeClassName="active"
>Hello</NavLink>

【讨论】:

这是在 wrapper 到链接。 这会输出一个锚标记。 OP 想要一些能输出列表项的东西。 这真的有效吗?我试过了,但它不适合我。【参考方案7】:

当您使用 react-redux 进行状态管理并且某些父组件 'connected' 到还原商店。 activeClassName 仅在页面刷新时应用到 Link,不会随着当前路由的变化而动态应用。

这与 react-redux 的 connect 函数有关,因为它抑制了上下文更新。要禁用对上下文更新的抑制,您可以在调用connect() 方法时设置pure: false,如下所示:

//your component which has the custom NavLink as its child. 
//(this component may be the any component from the list of 
//parents and grandparents) eg., header

function mapStateToProps(state) 
  return  someprops: state.someprops 


export default connect(mapStateToProps, null, null, 
  pure: false
)(Header);

在此处查看问题:reactjs#470

在此处查看pure: false 文档:docs

【讨论】:

【参考方案8】:

使用react-router-dom@4.3.1(尽管我猜应该可以使用任何4.x.x),我们可以使用withRouter HOC 来完成此操作。例如,我想实现 Bootstrap 导航栏,因为它需要在 &lt;li class="nav-item"&gt; 上而不是在锚标记上的 active 类,所以我创建了一个名为 NavItem 的新组件来封装单个 li.nav-item。实现如下:

import React from "react";
import  Link, withRouter  from "react-router-dom";

const NavItem = ( isActive, to, label ) => 
  let classes = ["nav-item"];
  if (isActive) classes.push("active");

  return (
    <li className=classes.join(" ")>
      <Link className="nav-link" to=to>
        label
      </Link>
    </li>
  );
;

export default withRouter(( location, ...props ) => 
  const isActive = location.pathname === props.to;

  console.log(location.pathname, props.to);

  return <NavItem ...props isActive=isActive />;
);

如您所见,NavItem 只是一个无状态功能组件,它需要一个 isActive 属性来确定是否应该添加 active 类。现在,要随着位置的变化更新这个道具,我们可以使用withRouter HOC。您可以将任何组件传递给此函数,它会在其 props 中为它提供 match, location, history 对象以及您传递的对象。在这里,我正在创建一个内联功能组件,它接收这些对象并使用location.pathname 属性确定当前链接是否为活动链接。这将给我们一个Boolean,我们可以返回NavItem以及isActive设置为我们使用location.pathname计算的值。

可以在here 找到一个工作示例。如果有更简单的方法,请告诉我。

【讨论】:

【参考方案9】:

从 react-router-dom@4.3.1 开始,我们可以轻松地使用带有 activeClassName 的 NavLink 而不是 Link。示例:

import React,  Component  from 'react';
import  NavLink  from 'react-router-dom';

class NavBar extends Component 
  render() 
    return (
      <div className="navbar">
        <ul>
          <li><NavLink to='/1' activeClassName="active">1</NavLink></li>
          <li><NavLink to='/2' activeClassName="active">2</NavLink></li>
          <li><NavLink to='/3' activeClassName="active">3</NavLink></li>
        </ul>
      </div>
    );
  

然后在你的 CSS 文件中:

.navbar li>.active 
  font-weight: bold;

NavLink 将根据当前 URL 将您的自定义样式属性添加到呈现的元素。

文档是here

【讨论】:

【参考方案10】:

在活动导航元素上设置类

import NavLink from 'react-router-dom';

&

&lt;NavLink to="/Home" activeClassName="active"&gt;Home&lt;/NavLink&gt;

【讨论】:

【参考方案11】:

这很容易做到,react-router-dom 提供了一切。

import React from 'react';
import  matchPath, withRouter  from 'react-router';
    
class NavBar extends React.Component 
  render()
    return(
       <ul className="sidebar-menu">
      <li className="header">MAIN NAVIGATION</li>
      <li className=matchPath(this.props.location.pathname,  path: "/dashboard" ) ? 'active' : ''><Link to="dashboard"><i className="fa fa-dashboard"></i> 
        <span>Dashboard</span></Link></li>
      <li className=matchPath(this.props.location.pathname,  path: "/email_lists" ) ? 'active' : ''><Link to="email_lists"><i className="fa fa-envelope-o"></i> 
        <span>Email Lists</span></Link></li>
      <li className=matchPath(this.props.location.pathname,  path: "/billing" ) ? 'active' : ''><Link to="billing"><i className="fa fa-credit-card"></i> 
        <span>Buy Verifications</span></Link></li>
    </ul>
      )
   

    
export default withRouter(NavBar);

使用 withRouter() 包装导航组件 HOC 将为您的组件提供一些道具: 1.匹配 2. 历史 3.位置

这里我使用了 react-router 的 matchPath() 方法来比较路径并决定 'li' 标签是否应该获得“活动”类名。我从 this.props.location.pathname 访问该位置。

当我们的链接被点击时,props 中的路径名称会发生​​变化,并且位置 props 会得到更新,NavBar 也会被重新渲染,并且活动样式会被应用

【讨论】:

【参考方案12】:

从路由器 v4 开始,我使用 'refs' 来设置父活动类:

<ul>
  <li>
    <NavLink
      innerRef=setParentAsActive
      activeClassName="is-active"
      to=link
    >
    text
  </NavLink>
</ul>

NavLinkinnerRef 属性接受回调函数,它将接收 DOM 节点作为参数。您可以使用任何可能的 DOM 操作,在这种情况下,只需将父元素 (&lt;li&gt;) 设置为具有相同的类:

  const setParentAsActive = node => 
    if (node) 
      node.parentNode.className = node.className;
    
  ;

缺点:

&lt;a&gt; 将有不必要的 is-active 类(因为您只需要 &lt;li&gt;),或者您可以在回调函数中删除该类。 如果您更改元素结构,f.e.将 a 标签包裹在 span 中,您的回调将停止工作,但可以编写更复杂的 DOM 遍历函数 你必须做一些 DOM 操作

【讨论】:

【参考方案13】:

只需使用NavLink 而不是Link。它将自动添加.active 类。

<Nav className="mr-auto">
    <Nav.Link as=NavLink to="/home">Home</Nav.Link>
    <Nav.Link as=NavLink to="/users">Users</Nav.Link>
</Nav>

【讨论】:

【参考方案14】:

扩展@BaiJiFeiLong 的答案,在链接中添加active= 属性:

<Nav.Link as=Link to="/user" active=pathname.startsWith('/user')>User</Nav.Link>

当任何路径以“/user”开头时,这将显示User 链接处于活动状态。要在每次路径更改时更新此内容,请在组件中包含 withRouter()

import React from 'react'
import  Link, withRouter  from 'react-router-dom'
import Navbar from 'react-bootstrap/Navbar'
import Nav from 'react-bootstrap/Nav'

function Header(props) 
    const pathname = props.location.pathname

    return (
        <Navbar variant="dark" expand="sm" bg="black">
            <Navbar.Brand as=Link to="/">
                Brand name
            </Navbar.Brand>
            <Navbar.Toggle aria-controls="basic-navbar-nav" />
            <Navbar.Collapse id="basic-navbar-nav">
                <Nav className="mr-auto">
                    <Nav.Link as=Link to="/user" active=pathname.startsWith('/user')>User</Nav.Link>
                    <Nav.Link as=Link to="/about" active=pathname.startsWith('/about')>About</Nav.Link>
                </Nav>
            </Navbar.Collapse>
        </Navbar>
    )


export default withRouter(Header)   // updates on every new page

【讨论】:

【参考方案15】:

使用 Jquery 进行活动链接:

$(function()
    $('#nav a').filter(function() 
        return this.href==location.href
    )
    .parent().addClass('active').siblings().removeClass('active')

    $('#nav a').click(function()
        $(this).parent().addClass('active').siblings().removeClass('active')
    )
);

使用 Jquery 中指定的组件生命周期方法或文档准备功能。

【讨论】:

老兄,React with JQuery 方法的问题回答错了【参考方案16】:

import React from 'react';
import withRouter, Link from "react-router-dom";

const SidenavItems = (props) => 
                                     // create simple list of links
    const items = [
        
            type: "navItem",
            icon: "home",
            text: "Home",
            link: "/",
            restricted: false
        ,
        
            type: "navItem",
            icon: "user-circle",
            text: "My Profile",
            link: "/user",
            restricted: false
        ,
        
            type: "navItem",
            icon: "sign-in",
            text: "Login",
            link: "/login",
            restricted: false
        ,
    ];

    const element = (item, i) =>   // create elements (Links)
                        // check if this is a current link on browser
        let active = "";

        if (props.location.pathname === item.link) 
            active = "active";
        

        return (
            <div key=i className=item.type>
                <Link
                    to=item.link
                    className=active // className will be set to "active" 
                >                      // or ""
                    item.text
                </Link>
            </div>
        )
    ;

    const showItems = () =>      // print elements
        return items.map((item, i) => 
            return element(item, i)
        )
    ;

    return (
        <div>
            showItems()  // print all the links we created in list
        </div>
    )
;
export default withRouter(SidenavItems);

【讨论】:

您好!虽然这段代码可以解决问题,including an explanation 解决问题的方式和原因确实有助于提高帖子的质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的回答添加解释并说明适用的限制和假设。 嗨!我添加了一些 cmets【参考方案17】:

你可以使用它的一种方式

当您使用功能组件时,请按照此处的说明进行操作。

在组件中添加变量 创建事件更改浏览器 URL 更改/或其他更改 重新分配当前路径(URL) 使用javascript匹配功能并设置为active或其他

在这里使用上面的代码。

import React,  useEffect  from 'react';
import  Link  from 'react-router-dom';

const NavItems = () => 
    let pathname = window.location.pathname;
    useEffect(() => 
        pathname = window.location.pathname;
    , [window.location.pathname]);

    return (
        <>
            <li className="px-4">
                <Link to="/home" className=`$pathname.match('/home') ? 'link-active' : ''`>Home</Link>
            </li>
            <li className="px-4">
                <Link to="/about-me" className=`$pathname.match('/about-me') ? 'link-active' : ''`>About-me</Link>
            </li>
            <li className="px-4">
                <Link to="/skill" className=`$pathname.match('/skill') ? 'link-active' : ''`>Skill</Link>
            </li>
            <li className="px-4">
                <Link to="/protfolio" className=`$pathname.match('/protfolio') ? 'link-active' : ''`>Protfolio</Link>
            </li>
            <li className="pl-4">
                <Link to="/contact" className=`$pathname.match('/contact') ? 'link-active' : ''`>Contact</Link>
            </li>
        </>
    );


export default NavItems;

--- 谢谢---

【讨论】:

是否可以匹配 2 条路径?因此,例如,如果其中一个路径为真,则将类设置为活动类似这样的内容:$pathname.match('/protfolio' || /anotherpath) @LyubomirIvanovValchev 您可以使用如下逻辑运算符: ($pathname.match('/protfolio') || $pathname.match("/anotherpath") )? '活动网址' : ' ' 如果我们在单个选项卡上有更多路径,您能否提出更好的方法【参考方案18】:

当前 React 路由器版本 5.2.0

activeStyle 是从 react-router-dom

导入的 NavLink 组件的默认 css 属性

这样我们就可以编写自己的自定义 css 来使其处于活动状态。在这个例子中,我将背景设置为透明,将文本设置为粗体。并将其存储在一个名为 isActive

的常量中
    import React from "react";
    import  NavLink from "react-router-dom";

    function nav() 

          const isActive = 
            fontWeight: "bold",
            backgroundColor: "rgba(255, 255, 255, 0.1)",
          ;
    
    return (
          <ul className="navbar-nav mr-auto">
            <li className="nav-item">
              <NavLink className="nav-link" to="/Shop" activeStyle=isActive>
                Shop
              </NavLink>
            </li>
          </ul>
          );

    export default nav;

【讨论】:

抛出错误:Error: Invariant failed: You should not use &lt;NavLink&gt; outside a &lt;Router&gt;【参考方案19】:

使用 React Hooks。

import React,  useState  from 'react';

export const Table = () => 

const [activeMenu, setActiveMenu] = useState('transaction');

return(
<>
 <Link className="flex-1 mr-2">
          <a
            id="transaction"
            className=
              activeMenu == 'transaction'
                ? 'text-center block border border-blue-500 rounded py-2 px-4 bg-blue-500 hover:bg-blue-700 text-white'
                : 'text-center block border border-white rounded hover:border-gray-200 text-blue-500 hover:bg-gray-200 py-2 px-4'
            
            href="#"
            onClick=() => 
              setActiveMenu('transaction');
            >
            Recent Transactions
          </a>
        </Link>
        <Link className="flex-1 mr-2">
          <a
            id="account"
            className=
              activeMenu == 'account'
                ? 'text-center block border border-blue-500 rounded py-2 px-4 bg-blue-500 hover:bg-blue-700 text-white'
                : 'text-center block border border-white rounded hover:border-gray-200 text-blue-500 hover:bg-gray-200 py-2 px-4'
            
            href="#"
            onClick=() => 
              setActiveMenu('account');
            >
            Account Statement
          </a>
        </LInk>

</>
)

【讨论】:

【参考方案20】:

对我来说有效的是使用 NavLink,因为它具有这个活动类属性。

    先导入

    import  NavLink  from 'react-router-dom';
    

    使用 activeClassName 获取活动类属性。

    <NavLink to="/" activeClassName="active">
     Home
    </NavLink>
    
    <NavLink to="/store" activeClassName="active">
     Store
    </NavLink>
    
    <NavLink to="/about" activeClassName="active">
     About Us
    </NavLink>
    

    通过属性 active 在 css 中为您的类设置样式。

    .active
      color:#fcfcfc;
     
    

【讨论】:

这行得通,谢谢,找到了关闭 Home 始终处于活动状态的解决方案:***.com/questions/51214763/…【参考方案21】:
<Navbar bg="light" expand="lg">
<Container>
    <Navbar.Brand>
        <Nav.Link as="NavLink" to="/">Brand Name</Nav.Link>
    </Navbar.Brand>
    <Navbar.Toggle aria-controls="basic-navbar-nav" />
    <Navbar.Collapse id="basic-navbar-nav">
        <nav className="me-auto">
            <Nav.Link as="NavLink" to="/" exact>Home</Nav.Link>
            <Nav.Link as="NavLink" to="/about">About</Nav.Link>
            <Nav.Link as="NavLink" to="/contact">Contact</Nav.Link>
            <NavDropdown title="Dropdown" id="basic-nav-dropdown">
                <Nav.Link as="NavLink" to="/page1">Dropdown Link 1</Nav.Link>
                <Nav.Link as="NavLink" to="/page2">Dropdown Link 2</Nav.Link>
                <Nav.Link as="NavLink" to="/page3">Dropdown Link 3</Nav.Link>
            </NavDropdown>
        </nav>
    </Navbar.Collapse>
</Container>

【讨论】:

一些解释会使这成为一个更好的答案。【参考方案22】:

在 react-router-dom 文档中,您使用 navlink 而不是链接。 https://v5.reactrouter.com/web/api/NavLink

import  NavLink  from "react-router-dom"; 
<Nav>
  <NavLink exact activeClassName="active--link" to="/" className="your class" > Home </NavLink> 
 <NavLink exact to="/classes" activeClassName="active--link" className="your class" > Classes </NavLink>
</Nav>
<NavLink to="/hello" activeClassName="active">Hello</NavLink>

【讨论】:

这并没有提供问题的答案。一旦你有足够的reputation,你就可以comment on any post;相反,provide answers that don't require clarification from the asker。 - From Review 从“react-router-dom”导入 NavLink ; @AbhishekDutt 我希望这会有所帮助.. ***.com/a/70359939/9166529【参考方案23】:

React 路由器 v6:

来源:Active NavLink Classes with React Router

您需要使用className 属性,该属性现在接受一个函数并传递一个isActive 布尔属性:

<NavLink
  to="users"
  className=( isActive ) => (isActive ? 'active' : 'inactive')
>
  Users
</NavLink>

这也非常适合添加多个类,并且是 v6 测试版中的一项重大更改:

<NavLink
  to="users"
  className=( isActive ) =>
    isActive ? 'bg-green-500 font-bold' : 'bg-red-500 font-thin'
  
>
  Users
</NavLink>

阅读更多内容和现场演示:Active NavLink Classes with React Router

【讨论】:

【参考方案24】:
<NavLink to='/' activeClassName='active'>
        Home
</NavLink>

我只是使用了NavLinkactiveClassName 没有将其包装在任何组件或其他东西中,但我的代码仍然有效:)

【讨论】:

以上是关于如何将活动类添加到 React Router 的链接?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Redux-Router + React-Router 将基本 URL 添加到应用程序

react-router:如果 <Link> 处于活动状态,如何禁用它?

使用 create-react-app 将 react-router-dom 添加到 react 应用程序时,为啥玩笑测试会中断

如何添加将使用 react-router-dom 渲染组件的路由?

如何在 react-router v4 中设置活动链接的样式?

如何从 express 重定向到 react-router?