在Angular中,如何确定活动路由?

注意: 这里有许多不同的答案,其中大多数在某个时期是有效的。事实上,随着Angular团队对路由器的改变,工作原理也发生了多次变化。在Angular中,最终将成为 The 路由器的Router 3.0版本打破了许多这些解决方案,但它提供了一个非常简单的解决方案。从RC.3开始,首选的解决方案是使用[routerLinkActive],如this answer

在Angular应用程序中(当前在2.0.0 beta版中)。当我写这篇文章时,0发布),你如何确定当前活动的路由是什么?

我正在开发一个使用Bootstrap 4的应用程序,我需要一种方法将导航链接/按钮标记为活动,当它们的相关组件显示在<router-output>标记中。

我意识到,当单击其中一个按钮时,我可以自己维护状态,但这不能涵盖进入同一路由的多条路径的情况(比如主导航菜单和主组件中的本地菜单)。

任何建议或链接将不胜感激。谢谢。

361795 次浏览

你可以通过将Location对象注入控制器并检查path()来检查当前路由,如下所示:

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


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

你必须确保首先导入它:

import {Location} from "angular2/router";

然后,您可以使用正则表达式与返回的路径进行匹配,以查看哪个路由是活动的。注意,不管你使用的是哪一个Location类,Location类都会返回一个规范化路径。所以即使你在使用HashLocationStragegy,返回的路径仍然是/foo/bar #/foo/bar的形式

我已经在另一个问题中回答了这个问题,但我相信它可能也与这个问题有关。以下是原始答案的链接: Angular 2:如何用参数确定活动路由? < / p >

我一直在尝试设置活跃的类,而不需要确切地知道当前位置(使用路由名称)。到目前为止,我得到的最好的解决方案是使用Router类中可用的函数isRouteActive

router.isRouteActive(instruction): Boolean接受一个参数,该参数是路由Instruction对象,并返回truefalse,无论该指令对当前路由是否为真。你可以使用Router生成(linkParams:数组)来生成路由Instruction。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>

到目前为止,这是我对这个问题的首选解决方案,它可能对你也有帮助。

我解决了在这个链接中遇到的一个问题,我发现你的问题有一个简单的解决方案。你可以在你的样式中使用router-link-active

@Component({
styles: [`.router-link-active { background-color: red; }`]
})
export class NavComponent {
}

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

我正在寻找一种方法来使用Twitter Bootstrap风格的导航与Angular2,但有麻烦得到active类应用到选定的链接的父元素。发现@alex-correia-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 ){}
}

下面是使用RouteData根据当前路由样式化菜单栏项的方法:

routecconfig包含了tab(当前路由)的数据:

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

如何确定当前活动的路由是什么?

更新:根据Angular2.4.x更新

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


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


route.snapshot.component; // active route's component


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

< a href = " https://angular.io/docs/ts/latest/api/router/index/ActivatedRoute-interface.html !#snapshot-anchor" rel="noreferrer">see more

在简单的情况下使用routerLinkActive很好,当有一个链接并且你想应用一些类时。但在更复杂的情况下,你可能没有routerLink,或者你需要更多的东西,你可以创建并使用:

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

不要忘记在管道依赖项中包含管道;)

Angular 2 RC中的Router不再定义isRouteActivegenerate方法。

urlTree -返回当前url树。

createUrlTree(commands: any[], segment?: RouteSegment) -应用命令数组到当前url树并创建一个新的url树。

尝试后

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

注意,routeSegment : RouteSegment必须注入到组件的构造函数中。

Router类的实例实际上是一个可观察对象,它每次改变时都会返回当前路径。我是这样做的:

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>

下面是在Angular版本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>

使用新的角的路由器,你可以在所有链接中添加[routerLinkActive]="['your-class-name']"属性:

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

如果只需要一个类,则使用简化的非数组格式:

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

如果只需要一个类,可以使用更简单的格式:

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

更多信息请参见文档记录不佳的routerLinkActive指令。(我主要是通过反复试验得出这个结论的。)

更新:更好的routerLinkActive指令文档现在可以在在这里中找到。(感谢@Victor Hugo Arango a在下面的评论中。)

另一个解决方案。在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>

可以使用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中的默认值

在Angular2 RC2中,你可以使用这个简单的实现

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

这将把类active添加到匹配url的元素中,阅读更多关于它的在这里

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

以下是迄今为止发布的所有Angular 2 RC版本对这个问题的答案:

RC4和RC3:

将类应用到link或link的祖先:

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

/home应该是URL,而不是路由的名称,因为name属性在路由器v3不再存在于路由对象中。

更多关于链接的routerLinkActive指令。

基于当前路由将class应用到任何div:

  • 将路由器注入组件的构造函数。
  • 用户路由器。Url进行比较。

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

RC2和RC1:

使用路由器组合。isRouteActive和class.*。例如,基于Home Route应用活动类。

Name和url都可以传递到router.generate中。

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

现在我正在使用rc。4与bootstrap 4和这个对我来说是完美的:

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

这将适用于url: /home

正如在已接受答案的注释中提到的,routerLinkActive指令也可以应用于实际的<a>标记的容器。

因此,例如与Twitter引导标签,其中active类应该应用于包含链接的<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>

非常简洁!我假设该指令检查标记的内容,并使用routerLink指令寻找<a>标记。

我正在使用angular路由器^3.4.7,我仍然有routerLinkActive指令的问题。

这是不工作,如果你有多个链接与相同的url加上它似乎不刷新所有的时间。

受到@tomaszbak答案的启发,我创建了一个小的组件来完成这项工作

让我们说你想添加CSS到我的active state/标签。使用routerLinkActive激活路由链接。

注意:'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>

对于Angular版本4+,你不需要使用任何复杂的解决方案。你可以简单地使用[routerLinkActive]="'is-active'"

举个例子,引导4导航链接:

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

我只是想添加一个不使用任何typescript的例子:

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

routerLinkActive变量被绑定到一个模板变量,然后根据需要重新使用。不幸的是,唯一需要注意的是,你不能把这些都放在<section>元素上,因为#home需要从之前解析到解析器击中<section>

对于angular 5用户来说,简单的解决方案是,将routerLinkActive添加到列表项中。

routerLinkActive指令通过routerLink指令与路由相关联。

它接受一个类数组作为输入,如果它的路由当前是活动的,它将把这些类添加到它所附加的元素中,如下所示:

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

如果我们当前正在查看主路由,上述操作将为锚标记添加一类active。

Demo

纯html模板就像

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

首先在.ts中导入RouterLinkActive

import {RouterLinkActive} from '@angular/router';

现在在HTML中使用RouterLinkActive

<span class="" routerLink ="/some_path" routerLinkActive="class_Name">Value</span></a>

为类“class_Name”提供一些css,因为当这个链接被激活/单击时,你会在span检查时发现这个类。

从Angular 8开始,它可以工作:

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

{ exact: true }确保它匹配url。

在angular的最新版本中,你可以简单地检查router.isActive(routeNameAsString)。例如,请看下面的例子:

 <div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item" [class.active] = "router.isActive('/dashboard')">
<a class="nav-link" href="#">داشبورد <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item" [class.active] = "router.isActive(route.path)" *ngFor="let route of (routes$ | async)">
<a class="nav-link" href="javascript:void(0)" *ngIf="route.childRoutes && route.childRoutes.length > 0"
[matMenuTriggerFor]="menu">\{\{route.name}}</a>
<a class="nav-link" href="\{\{route.path}}"
*ngIf="!route.childRoutes || route.childRoutes.length === 0">\{\{route.name}}</a>
<mat-menu #menu="matMenu">
<span *ngIf="route.childRoutes && route.childRoutes.length > 0">
<a *ngFor="let child of route.childRoutes" class="nav-link" href="\{\{route.path + child.path}}"
mat-menu-item>\{\{child.name}}</a>
</span>
</mat-menu>
</li>
</ul>
<span class="navbar-text mr-auto">
<small>سلام</small> \{\{ (currentUser$ | async) ? (currentUser$ | async).firstName : 'کاربر' }}
\{\{ (currentUser$ | async) ? (currentUser$ | async).lastName : 'میهمان' }}
</span>
</div>

确保你没有忘记在你的组件中注入路由器。

在2020年,如果你想在没有[routerLink]的元素上设置active类,你可以简单地做:

<a
(click)="bookmarks()"
[class.active]="router.isActive('/string/path/'+you+'/need', false)" // <== you need this one. second argument 'false' - exact: true/false
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
>
bookmarks
</a>


一种程序化的方式是在组件本身中完成。我在这个问题上挣扎了三周,但最终放弃了angular文档,转而阅读了让routerlinkactive工作的实际代码,这是我能找到的最好的文档了。

    import {
Component,AfterContentInit,OnDestroy, ViewChild,OnInit, ViewChildren, AfterViewInit, ElementRef, Renderer2, QueryList,NgZone,ApplicationRef
}
from '@angular/core';
import { Location } from '@angular/common';


import { Subscription } from 'rxjs';
import {
ActivatedRoute,ResolveStart,Event, Router,RouterEvent, NavigationEnd, UrlSegment
} from '@angular/router';
import { Observable } from "rxjs";
import * as $ from 'jquery';
import { pairwise, map } from 'rxjs/operators';
import { filter } from 'rxjs/operators';
import {PageHandleService} from '../pageHandling.service'
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})








export class HeaderComponent implements AfterContentInit,AfterViewInit,OnInit,OnDestroy{


public previousUrl: any;
private subscription: Subscription;




@ViewChild("superclass", { static: false } as any) superclass: ElementRef;
@ViewChildren("megaclass") megaclass: QueryList<ElementRef>;




constructor( private element: ElementRef, private renderer: Renderer2, private router: Router, private activatedRoute: ActivatedRoute, private location: Location, private pageHandleService: PageHandleService){
this.subscription = router.events.subscribe((s: Event) => {
if (s instanceof NavigationEnd) {
this.update();
}
});




}




ngOnInit(){


}




ngAfterViewInit() {
}


ngAfterContentInit(){
}






private update(): void {
if (!this.router.navigated || !this.superclass) return;
Promise.resolve().then(() => {
this.previousUrl = this.router.url


this.megaclass.toArray().forEach( (superclass) => {


var superclass = superclass
console.log( superclass.nativeElement.children[0].classList )
console.log( superclass.nativeElement.children )


if (this.previousUrl == superclass.nativeElement.getAttribute("routerLink")) {
this.renderer.addClass(superclass.nativeElement.children[0], "box")
console.log("add class")


} else {
this.renderer.removeClass(superclass.nativeElement.children[0], "box")
console.log("remove class")
}


});
})
//update is done
}
ngOnDestroy(): void { this.subscription.unsubscribe(); }




//class is done
}
< p > 请注意: < br > 对于编程方式,请确保添加router-link,并且它接受一个子元素。如果你想改变这一点,你需要去除superclass.nativeElement上的子元素

这对我的主动/非主动路线有帮助:

<a routerLink="/user/bob" routerLinkActive #rla="routerLinkActive" [ngClass]="rla.isActive ? 'classIfActive' : 'classIfNotActive'">
</a>

< a href = " https://stackoverflow.com/a/41982420/3411787 " > Ref < / >