В Angular как вы определяете активный маршрут?

192

ПРИМЕЧАНИЕ. Здесь есть много разных ответов, и большинство из них были действительны в тот или иной момент. Дело в том, что то, что работает, несколько раз менялось, когда команда Angular изменила свой маршрутизатор. Версия Router 3.0, которая в конечном итоге будет маршрутизатором в Angular, ломает многие из этих решений, но предлагает очень простое решение. Начиная с RC.3, предпочтительным решением является использование [routerLinkActive], как показано в этом ответе.

В приложении Angular (текущем в версии 2.0.0-beta.0, когда я пишу это), как вы определяете, каков текущий активный маршрут?

Я работаю над приложением, использующим Bootstrap 4, и мне нужен способ отметить ссылки/кнопки навигации как активные, когда их связанный компонент отображается в теге <router-output>.

Я понимаю, что я мог сам поддерживать состояние, когда нажата одна из кнопок, но это не будет охватывать случай наличия нескольких путей в одном и том же маршруте (скажем, главное меню навигации, а также локальное меню в основной компонент).

Любые предложения или ссылки будут оценены. Спасибо.

Теги:
angular
angular2-routing

24 ответа

244
Лучший ответ

С помощью нового Angular router вы можете добавить атрибут [routerLinkActive]="['your-class-name']" ко всем вашим ссылкам:

<a [routerLink]="['/home']" [routerLinkActive]="['is-active']">Home</a>

Или упрощенный формат без массива, если требуется только один класс:

<a [routerLink]="['/home']" [routerLinkActive]="'is-active'">Home</a>

Подробную информацию см. в плохо документированной директиве routerLinkActive. (Я в основном понял это путем проб и ошибок.)

UPDATE: теперь можно найти лучшую документацию для директивы routerLinkActive здесь. (Спасибо @Victor Hugo Arango A. в комментариях ниже.)

  • 0
    Обратите внимание, что вам нужно добавить вышеуказанную директиву ко всем ссылкам. Тогда is-active будет добавлен как класс только к активной ссылке.
  • 4
    Есть ли способ активировать его, когда активны дети маршрута? В коде есть @input для параметров, но exact: false активирует класс всякий раз, когда братья и сестры текущего маршрута также активны.
Показать ещё 8 комментариев
68

Я ответил на это в другом вопросе, но я считаю, что это может иметь отношение и к этому. Здесь ссылка на исходный ответ: Angular 2: Как определить активный маршрут с параметрами?

Я пытаюсь установить класс active, не зная точно, что такое текущее местоположение (используя имя маршрута). Лучшим решением, которое я получил до сих пор, является использование функции isRouteActive, доступной в классе Router.

router.isRouteActive(instruction): Boolean принимает один параметр, который является объектом маршрута Instruction и возвращает true или false, истинна ли эта инструкция или нет для текущего маршрута. Вы можете создать маршрут Instruction, используя Router generate (linkParams: Array). LinkParams следует в том же формате, что и значение, переданное в директиву routerLink (например, router.isRouteActive(router.generate(['/User', { user: user.id }]))).

Вот как RouteConfig может выглядеть как (я немного изменил его, чтобы показать использование параметров):

@RouteConfig([
  { path: '/', component: HomePage, name: 'Home' },
  { path: '/signin', component: SignInPage, name: 'SignIn' },
  { path: '/profile/:username/feed', component: FeedPage, name: 'ProfileFeed' },
])

И Вид будет выглядеть так:

<li [class.active]="router.isRouteActive(router.generate(['/Home']))">
   <a [routerLink]="['/Home']">Home</a>
</li>
<li [class.active]="router.isRouteActive(router.generate(['/SignIn']))">
   <a [routerLink]="['/SignIn']">Sign In</a>
</li>
<li [class.active]="router.isRouteActive(router.generate(['/ProfileFeed', { username: user.username }]))">
    <a [routerLink]="['/ProfileFeed', { username: user.username }]">Feed</a>
</li>

Это было мое предпочтительное решение проблемы до сих пор, это может быть полезно и вам.

  • 1
    Я думаю, что это решение лучше принятого, поскольку оно использует Angular API вместо регулярных выражений, соответствующих пути. Это все еще немного уродливо, хотя было бы неплохо иметь возможность сделать router.isRouteActive('Home') .
  • 0
    @Philip Я согласен с вами, это хороший способ отделить его от реального пути, но он не так хорош, как я ожидал. Я думаю, вы могли бы написать обертку вокруг нее и сделать ее намного меньше, что улучшило бы читаемость.
Показать ещё 12 комментариев
32

Я решил проблему, с которой я столкнулся в этой ссылке, и я выяснил, что есть простое решение для вашего вопроса. Вы можете использовать router-link-active вместо этого в своих стилях.

@Component({
   styles: [`.router-link-active { background-color: red; }`]
})
export class NavComponent {
}
  • 2
    Я считаю, что это должен быть принятый ответ. Маршрутизатор Angular2 добавит это автоматически для вас.
  • 2
    к сожалению, этот класс добавляют на <a>, а не на <li>
Показать ещё 1 комментарий
28

Небольшое улучшение ответа @alex-correia-santos на основе https://github.com/angular/angular/pull/6407#issuecomment-190179875

import {Router, RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
// ...
export class App {
  constructor(private router: Router) {
  }

  // ...

  isActive(instruction: any[]): boolean {
    return this.router.isRouteActive(this.router.generate(instruction));
  }
} 

И используйте его следующим образом:

<ul class="nav navbar-nav">
    <li [class.active]="isActive(['Home'])">
        <a [routerLink]="['Home']">Home</a>
    </li>
    <li [class.active]="isActive(['About'])">
        <a [routerLink]="['About']">About</a>
    </li>
</ul>
  • 0
    и стиль в styles : [ компонентов styles : [ .active {background-color: aliceblue; } ] . +1 это работает
  • 0
    Отличное решение, с этим вы можете сделать маршрутизатор частным.
Показать ещё 1 комментарий
28

Вы можете проверить текущий маршрут, введя объект Location в свой контроллер и проверив path(), например:

class MyController {
    constructor(private location:Location) {}

    ...  location.path(); ...
}

Вам нужно будет сначала его импортировать:

import {Location} from "angular2/router";

Затем вы можете использовать регулярное выражение для соответствия пути, возвращаемому для просмотра того, какой маршрут активен. Обратите внимание, что класс Location возвращает нормализованный путь, независимо от того, какой LocationStrategy вы используете. Поэтому, даже если вы используете HashLocationStragegy, возвращаемые пути будут по-прежнему иметь форму /foo/bar not #/foo/bar

15

как вы определяете, каков текущий активный маршрут?

ОБНОВЛЕНИЕ: обновлено согласно Angular2.4.x

constructor(route: ActivatedRoute) {
   route.snapshot.params; // active route params

   route.snapshot.data; // active route resolved data

   route.snapshot.component; // active route component

   route.snapshot.queryParams // The query parameters shared by all the routes
}

подробнее...

6

Решение для Angular2 RC 4:

import {containsTree} from '@angular/router/src/url_tree';
import {Router} from '@angular/router';

export function isRouteActive(router: Router, route: string) {
   const currentUrlTree = router.parseUrl(router.url);
   const routeUrlTree = router.createUrlTree([route]);
   return containsTree(currentUrlTree, routeUrlTree, true);
}
6

Чтобы отметить активные маршруты routerLinkActive, можно использовать

<a [routerLink]="/user" routerLinkActive="some class list">User</a>

Это также работает с другими элементами, такими как

<div routerLinkActive="some class list">
  <a [routerLink]="/user">User</a>
</div>

Если частичные соответствия также должны быть отмечены, используйте

routerLinkActive="some class list" [routerLinkActiveOptions]="{ exact: false }"

Насколько я знаю, exact: false будет по умолчанию в RC.4

6

Здесь приведен полный пример добавления активного стиля маршрута в Angular version 2.0.0-rc.1, который учитывает пустые корневые пути (например, path: '/')

app.component.ts → Маршруты

import { Component, OnInit } from '@angular/core';
import { Routes, Router, ROUTER_DIRECTIVES } from '@angular/router';
import { LoginPage, AddCandidatePage } from './export';
import {UserService} from './SERVICES/user.service';

@Component({
  moduleId: 'app/',
  selector: 'my-app',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.css'],
  providers: [UserService],
  directives: [ROUTER_DIRECTIVES]
})

@Routes([
  { path: '/', component: AddCandidatePage },
  { path: 'Login', component: LoginPage }
])
export class AppComponent  { //implements OnInit

  constructor(private router: Router){}

  routeIsActive(routePath: string) {
     let currentRoute = this.router.urlTree.firstChild(this.router.urlTree.root);
     // e.g. 'Login' or null if route is '/'
     let segment = currentRoute == null ? '/' : currentRoute.segment;
     return  segment == routePath;
  }
}

app.component.html

<ul>
  <li [class.active]="routeIsActive('Login')"><a [routerLink]="['Login']" >Login</a></li>
  <li [class.active]="routeIsActive('/')"><a [routerLink]="['/']" >AddCandidate</a></li>
</ul>
<route-outlet></router-outlet>
6

Ниже приведен метод, использующий RouteData для стилизации элементов menuBar в зависимости от текущего маршрута:

RouteConfig включает данные с вкладкой (текущий маршрут):

@RouteConfig([
  {
    path: '/home',    name: 'Home',    component: HomeComponent,
    data: {activeTab: 'home'},  useAsDefault: true
  }, {
    path: '/jobs',    name: 'Jobs',    data: {activeTab: 'jobs'},
    component: JobsComponent
  }
])

Кусок макета:

  <li role="presentation" [ngClass]="{active: isActive('home')}">
    <a [routerLink]="['Home']">Home</a>
  </li>
  <li role="presentation" [ngClass]="{active: isActive('jobs')}">
    <a [routerLink]="['Jobs']">Jobs</a>
  </li>

Класс:

export class MainMenuComponent {
  router: Router;

  constructor(data: Router) {
    this.router = data;
  }

  isActive(tab): boolean {
    if (this.router.currentInstruction && this.router.currentInstruction.component.routeData) {
      return tab == this.router.currentInstruction.component.routeData.data['activeTab'];
    }
    return false;
  }
}
5

Прямо сейчас я использую rc.4 с bootstrap 4, и этот работает идеально для меня:

 <li class="nav-item" routerLinkActive="active" [routerLinkActiveOptions]="{exact:
true}">
    <a class="nav-link" [routerLink]="['']">Home</a>
</li>

Это будет работать для url:/home

  • 0
    Какова цель точного варианта? Делает ли это, что это не соответствует подпутям как /home/whatever ?
  • 0
    да, exact означает, что этот маршрут будет иметь то же имя. И это необходимо, если вы планируете использовать его с такими инструментами, как Twitter bootstrap. Он уже обрабатывает активное состояние ссылки и без exact параметра не будет работать. (не уверен, как это работает в ядре, я попробовал, и это работает для меня)
Показать ещё 2 комментария
5

Router в Angular 2 RC больше не определяет методы isRouteActive и generate.

urlTree - Возвращает текущее дерево url.

createUrlTree(commands: any[], segment?: RouteSegment) - Применяет массив команд к текущему дереву url и создает новое дерево url.

Попробуйте выполнить

<li 
[class.active]=
"router.urlTree.contains(router.createUrlTree(['/SignIn', this.routeSegment]))">

routeSegment : RouteSegment должно быть введено в конструктор компонента.

4

Как упоминалось в одном из комментариев принятого ответа, директива routerLinkActive также может быть применена к контейнеру фактического тега <a>.

Итак, например с вкладками Twitter Bootstrap, где активный класс должен быть применен к тегу <li>, который содержит ссылку:

<ul class="nav nav-tabs">
    <li role="presentation" routerLinkActive="active">
        <a routerLink="./location">Location</a>
    </li>
    <li role="presentation" routerLinkActive="active">
        <a routerLink="./execution">Execution</a>
    </li>
</ul>

Довольно аккуратно! Я полагаю, что директива проверяет содержимое тега и ищет тег <a> с директивой routerLink.

4

Ниже приведены ответы на этот вопрос для всех версий версий Angular 2 RC, выпущенных до даты:

RC4 и RC3:

Для применения класса к ссылке или предку ссылки:

<li routerLinkActive="active"><a [routerLink]="['/home']">Home</a></li>

/home должен быть URL, а не имя маршрута, поскольку свойство имени больше не существует в объекте маршрута с маршрутизатора v3.

Подробнее о директиве routerLinkActive на link.

Для применения класса к любому div на основе текущего маршрута:

  • Inject Router в конструктор компонента.
  • Пользователь router.url для сравнения.

например

<nav [class.transparent]="router.url==('/home')">
</nav>

RC2 и RC1:

Используйте комбинацию router.isRouteActive и class. *. например, применять активный класс на основе Home Route.

Имя и URL могут быть переданы в router.generate.

 <li [class.active]="router.isRouteActive(router.generate(['Home']))">
    <a [routerLink]="['Home']" >Home</a>
</li>
4

В Angular2 RC2 вы можете использовать эту простую реализацию

<a [routerLink]="['/dashboard']" routerLinkActive="active">Dashboard</a>

это добавит класс active к элементу с соответствующим URL-адресом, подробнее об этом здесь

4

Другой способ обхода проблемы. Гораздо проще в Angular Router V3 Alpha. путем ввода маршрутизатора

import {Router} from "@angular/router";

export class AppComponent{

    constructor(private router : Router){}

    routeIsActive(routePath: string) {
        return this.router.url == routePath;
    }
}

Использование

<div *ngIf="routeIsActive('/')"> My content </div>
  • 0
    как только я импортирую его, я получаю свойство Cannot read isSkipSelf с нулевой ошибкой. есть идеи?
4

Экземпляр класса Router на самом деле является Observable и он возвращает текущий путь каждый раз, когда он изменяется. Вот как я это делаю:

export class AppComponent implements OnInit { 

currentUrl : string;

constructor(private _router : Router){
    this.currentUrl = ''
}

ngOnInit() {
    this._router.subscribe(
        currentUrl => this.currentUrl = currentUrl,
        error => console.log(error)
    );
}

isCurrentRoute(route : string) : boolean {
    return this.currentUrl === route;
 } 
}

И затем в моем HTML:

<a [routerLink]="['Contact']" class="item" [class.active]="isCurrentRoute('contact')">Contact</a>
  • 1
    .subscribe недоступно на экземпляре маршрутизатора.
4

Использование routerLinkActive хорош в простых случаях, когда есть ссылка, и вы хотите применить некоторые классы. Но в более сложных случаях, когда у вас может не быть routerLink или где вам нужно что-то еще, вы можете создать и использовать pipe:

@Pipe({
    name: "isRouteActive",
    pure: false
})
export class IsRouteActivePipe implements PipeTransform {

    constructor(private router: Router,
                private activatedRoute: ActivatedRoute) {
    }

    transform(route: any[], options?: { queryParams?: any[], fragment?: any, exact?: boolean }) {
        if (!options) options = {};
        if (options.exact === undefined) options.exact = true;

        const currentUrlTree = this.router.parseUrl(this.router.url);
        const urlTree = this.router.createUrlTree(route, {
            relativeTo: this.activatedRoute,
            queryParams: options.queryParams,
            fragment: options.fragment
        });
        return containsTree(currentUrlTree, urlTree, options.exact);
    }
}

то

<div *ngIf="['/some-route'] | isRouteActive">...</div>

и не забудьте включить трубку в зависимости от труб;)

  • 0
    Хорошая идея, но в angular2.0.0rc3 я изменяю this.router.isRouteActive ... на this._location.path () и помещаю его сверху: import {Location} из '@ angular / common';
  • 1
    Кажется, что-то отсутствует в коде. Где определено containsTree дерево?
3

Для Angular версии 4+ вам не нужно использовать какое-либо сложное решение. Вы можете просто использовать [routerLinkActive]="'is-active'".

Для примера с bootstrap 4 nav link:

    <ul class="navbar-nav mr-auto">
      <li class="nav-item" routerLinkActive="active">
        <a class="nav-link" routerLink="/home">Home</a>
      </li>
      <li class="nav-item" routerLinkActive="active">
        <a class="nav-link" routerLink="/about-us">About Us</a>
      </li>
      <li class="nav-item" routerLinkActive="active">
        <a class="nav-link " routerLink="/contact-us">Contact</a>
      </li>
    </ul>
1

скажем, вы хотите добавить CSS в мое активное состояние/вкладку. Используйте routerLinkActive, чтобы активировать вашу маршрутную ссылку.

note: "active" - это мое имя класса здесь

<style>
   .active{
       color:blue;
     }
</style>

  <a routerLink="/home" [routerLinkActive]="['active']">Home</a>
  <a routerLink="/about" [routerLinkActive]="['active']">About</a>
  <a routerLink="/contact" [routerLinkActive]="['active']">Contact</a>
1

Я искал способ использования стиля загрузки Bootstrap в Twitter с помощью Angular2, но не удалось получить класс active, примененный к родительскому элементу выбранной ссылки. Найдено, что решение @alex-rectia-santos отлично работает!

Компонент, содержащий ваши вкладки, должен импортировать маршрутизатор и определить его в своем конструкторе, прежде чем вы сможете сделать необходимые вызовы.

Вот упрощенная версия моей реализации...

import {Component} from 'angular2/core';
import {Router, RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
import {HomeComponent} from './home.component';
import {LoginComponent} from './login.component';
import {FeedComponent} from './feed.component';

@Component({
  selector: 'my-app',
  template: `
    <ul class="nav nav-tabs">
      <li [class.active]="_r.isRouteActive(_r.generate(['Home']))">
        <a [routerLink]="['Home']">Home</a>
      </li>
      <li [class.active]="_r.isRouteActive(_r.generate(['Login']))">
        <a [routerLink]="['Login']">Sign In</a>
      </li>
      <li [class.active]="_r.isRouteActive(_r.generate(['Feed']))">
        <a [routerLink]="['Feed']">Feed</a>
      </li>
    </ul>`,
  styleUrls: ['app/app.component.css'],
  directives: [ROUTER_DIRECTIVES]
})
@RouteConfig([
  { path:'/', component:HomeComponent, name:'Home', useAsDefault:true },
  { path:'/login', component:LoginComponent, name:'Login' },
  { path:'/feed', component:FeedComponent, name:'Feed' }
])
export class AppComponent {
  title = 'My App';
  constructor( private _r:Router ){}
}
0

Простое решение для angular 5 пользователей, просто добавьте routerLinkActive в элемент списка.

Директива

A routerLinkActive связана с маршрутом через директиву routerLink.

В качестве ввода вводится массив классов, который он добавит к элементу, к которому он присоединен, если его маршрут в настоящее время активен, например:

<li class="nav-item"
    [routerLinkActive]="['active']">
  <a class="nav-link"
     [routerLink]="['home']">Home
  </a>
</li>

Вышеупомянутый класс добавит класс активного к тегу привязки, если мы сейчас просматриваем домашний маршрут.

Изображение 3465

0

Просто подумал, что добавлю в пример, который не использует никаких typescript:

<input type="hidden" [routerLink]="'home'" routerLinkActive #home="routerLinkActive" />
<section *ngIf="home.isActive"></section>

Переменная routerLinkActive привязана к переменной шаблона и затем повторно используется по мере необходимости. К сожалению, единственное предостережение состоит в том, что вы не можете иметь все это в элементе <section>, поскольку #home необходимо разрешить до для удара синтаксического анализатора <section>.

0

Я использую angular router ^3.4.7, и у меня все еще возникают проблемы с директивой routerLinkActive.

Он не работает, если у вас есть несколько ссылок с тем же URL-адресом, и он, кажется, не обновляется все время.

Вдохновленный ответом @tomaszbak, я создал маленький компонент для выполнения задания

Ещё вопросы

Сообщество Overcoder
Наверх
Меню