Подтвердить что ты не робот

Как добавить активный класс в ссылку из 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>

Я хочу установить класс для активного пути active в элементе обтекания <li>. Я вижу, что есть и другие решения, которые показывают, как это сделать, например условно установить активный класс в меню, используя текущий маршрут реагирующего маршрутизатора, однако я не думаю, что это лучший способ установить активный класс в обертка для Link.

Я также нашел https://github.com/insin/react-router-active-component, но кажется, что в этом нет необходимости.

Возможно ли это в React Router или мне нужно использовать внешнее решение?

4b9b3361

Ответ 1

В компоненте Link теперь вы можете добавить activeClassName или установить activeStyle.

Это позволяет вам легко добавлять стили к активной в данный момент ссылке.


Ранее вы могли создать пользовательский компонент, который работает как оболочка для Link со следующей логикой.

В файле с именем 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>

Ответ 2

React-Router V4 поставляется с компонентом NavLink из коробки

Чтобы использовать, просто установите атрибут activeClassName для класса, который вы соответствующим образом стилизовали, или непосредственно установите activeStyle для стилей, которые вы хотите. Смотрите документы для более подробной информации.

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

Ответ 3

Ответ обновлен с 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;

Затем используйте его, как описано выше.

Ответ 4

Мне не понравилась идея создания настраиваемого компонента, потому что, если у вас есть другой элемент упаковки, вам придется создать другой настраиваемый компонент и т.д. Кроме того, это просто избыток. Поэтому я просто сделал это с помощью 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, но делает якорь заполнением ли и стилирует его.

Ответ 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 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>
    );}}

Ответ 6

Вы можете реально воспроизвести то, что находится внутри 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 исходный код и удалите ненужные части;)

Ответ 7

С [email protected] (хотя любой 4.xx должен делать, я думаю), мы можем использовать 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 prop, чтобы определить, должен ли быть добавлен active класс. Теперь, чтобы обновить этот реквизит при изменении местоположения, мы можем использовать withRouter HOC. Вы можете передать любой компонент этой функции, и он предоставит ей { match, location, history } объекты в своих реквизитах вместе с теми, которые вы передадите. Здесь я создаю встроенный функциональный компонент, который получает эти объекты и определяет, является ли текущая ссылка активной, используя свойство location.pathname. Это даст нам Boolean и мы можем вернуть NavItem вместе с isActive установленным в значение, которое мы вычислили с помощью location.pathname.

Рабочий пример этого можно найти здесь. Пожалуйста, дайте мне знать, если есть более простой способ сделать это.

Ответ 8

Чтобы установить класс на активный элемент навигации

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

&

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

Ответ 9

Что касается [email protected], мы можем легко использовать NavLink с activeClassName вместо 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.

Документ здесь

Ответ 10

Это очень легко сделать, реагирует-маршрутизатор-дом предоставляет все.

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

Ответ 11

В ответе Vijey есть небольшая проблема, когда вы используете response-redux для управления состоянием, а некоторые из родительских компонентов "подключены" к хранилищу redux. ActiveClassName применяется к Link только при обновлении страницы и не применяется динамически при изменении текущего маршрута.

Это связано с функцией connect-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);

Проверьте проблему здесь: responsejs # 470

Проверьте pure: false документация здесь: docs

Ответ 12

Начиная с router v4, я использую refs для установки родительского активного класса:

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

NavLink innerRef prop принимает функцию обратного вызова, которая получит узел DOM в качестве аргумента. Тогда вы можете использовать любые возможные манипуляции с DOM, в этом случае просто установите родительский элемент (<li>) для того же класса:

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

Недостатки:

  • <a> будет ненужный класс is-active (так как он нужен только для <li>), или вы можете удалить этот класс в функции обратного вызова.
  • если изменить структуру элемента, Fй обернуть 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.