如何从React路由器向链接添加活动类?

时间:2015-12-22 14:35:54

标签: react-router

我使用Link创建了一个自举式边栏。以下是我的代码片段:

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

I want to set the class for the active path to `active` on the wrapping element `<li>`. I see there are other solutions out there that show how to do this *kindof* (https://stackoverflow.com/questions/34410051/conditionally-set-active-class-on-menu-using-react-router-current-route), however I don't think that is the best way to set an active class on a wrapper to a `Link`.

I also found https://github.com/insin/react-router-active-component but it feels like it is unnecessary.

In React Router, is this possible or do I need to use an external solution?

20 个答案:

答案 0 :(得分:72)

在链接组件上,您现在可以添加 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>

答案 1 :(得分:24)

React-Router V4 附带开箱即用的NavLink组件

要使用,只需将activeClassName属性设置为您已适当设置样式的类,或直接将activeStyle设置为您想要的样式。有关详细信息,请参阅the docs

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

答案 2 :(得分:12)

使用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;

然后如上所述使用它。

答案 3 :(得分:6)

我不喜欢创建自定义组件的想法,因为如果你有一个不同的包装元素,你将不得不创建另一个自定义组件等。此外,它只是矫枉过正。所以我只是使用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 :(得分:5)

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

  1. 首先导入

    import { NavLink } from 'react-router-dom';
    
  2. 使用activeClassName获取活动类属性。

    <NavLink to="/" activeClassName="active">
     Home
    </NavLink>
    
    <NavLink to="/store" activeClassName="active">
     Store
    </NavLink>
    
    <NavLink to="/about" activeClassName="active">
     About Us
    </NavLink>
    
  3. 通过active属性在CSS中设置类的样式。

    .active{
      color:#fcfcfc;
     }
    

答案 5 :(得分:5)

这是我的方式,使用道具的位置。 我不知道但是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 class="nav navbar-nav navbar-right">
        <li class={homeClass}><Link to="/">Home</Link></li>
        <li class={aboutClass}><Link to="about" activeClassName="active">About</Link></li>
        <li class={contactClass}><Link to="contact" activeClassName="active">Contact</Link></li>
      </ul>

</div>
    );}}

答案 6 :(得分:3)

你实际上可以复制here里面的内容

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源代码并删除不需要的部分;)

答案 7 :(得分:2)

使用react-router-dom@4.3.1(尽管我猜测任何4.x.x),我们可以使用withRouter HOC来完成此任务。例如,我想实现Bootstrap导航栏,因为它需要active上的<li class="nav-item">类,而不是锚标记,我创建了一个名为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。您可以将任何组件传递给此函数,并且它会在其道具中提供{ match, location, history }个对象以及您传递的对象。在这里,我正在创建一个内联的功能组件,它接收这些对象并使用location.pathname属性确定当前链接是否是活动链接。这将给我们Boolean,我们可以将NavItemisActive设置为我们使用location.pathname计算的值。

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

答案 8 :(得分:2)

只需使用round (((`tbl_products`.`cost` * (`tbl_tax`.`amount` / 100)) + `tbl_products`.`cost`),n) 而不是NavLink。它将自动添加Link类。

.active

答案 9 :(得分:2)

当前反应路由器版本5.2.0

activeStyle 是NavLink组件的默认CSS属性,该属性是从 react-router-dom

导入的

因此我们可以编写自己的自定义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;

答案 10 :(得分:1)

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

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

答案 11 :(得分:1)

要在活动导航元素上设置类

import { NavLink } from 'react-router-dom';

<NavLink to="/Home" activeClassName="active">Home</NavLink>

答案 12 :(得分:1)

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

答案 13 :(得分:1)

一种使用方式

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

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

在此处使用上面的代码。

window.addEventListener("load", function(){
  alert("hi")
});

---谢谢---

答案 14 :(得分:0)

当您使用 react-redux 进行状态管理并且某些父组件'connected'时,Vijey的答案有点问题redux商店。 activeClassName 仅在刷新页面时应用于链接,并且在当前路由更改时不会动态应用。

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

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

答案 15 :(得分:0)

做到这一点非常容易,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访问位置。

点击我们的链接时,将在道具中更改路径名称,位置道具将被更新NavBar也将被重新渲染并采用活动样式

答案 16 :(得分:0)

自路由器v4起,我使用'refs'来设置父活动类:

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

NavLink的{​​{1}}道具接受回调函数,该函数将接收DOM节点作为参数。您可以使用任何可能的DOM操作,在这种情况下,只需将父元素(innerRef)设置为具有相同的类:

<li>

缺点:

  • const setParentAsActive = node => { if (node) { node.parentNode.className = node.className; } }; 将具有不必要的<a>类(因为您仅需要is-active使用它),或者您可以在回调函数中删除该类。
  • 如果您更改元素结构,则将<li>标签包裹在a内,您的回调将停止工作,但是可以编写更复杂的DOM遍历函数
  • 您必须进行一些DOM操作

答案 17 :(得分:0)

扩展@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

答案 18 :(得分:0)

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

</>
)
}

答案 19 :(得分:-3)

使用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中指定的组件生命周期方法或文档准备功能。