场景,后台自定义底部菜单激活样式,如用户定义的数据为
{
color: '#000',
selectedColor: 'red'
}
复制代码
angular提供RouterLinkActive显然不够用了,文档原文说的很清楚,他是css class!
Lets you add a CSS class to an element when the link's route becomes active.
复制代码
下面仿照RouterLinkActive实现一个RouterLinkActiveStyle,下面是RouterLinkActive,通过分析标注需要修改的地方,用todo标注。
import {
AfterContentInit,
ChangeDetectorRef,
ContentChildren,
Directive,
ElementRef,
Input,
OnChanges,
OnDestroy,
QueryList,
Renderer2,
SimpleChanges
} from '@angular/core';
import { Subscription } from 'rxjs';
import {
NavigationEnd,
RouterEvent,
Router,
RouterLink,
RouterLinkWithHref
} from '@angular/router';
// 修改雷鸣和selector,避免冲突
@Directive({
selector: '[routerLinkActiveStyle]',
exportAs: 'routerLinkActiveStyle'
})
export class RouterLinkActiveStyle
implements OnChanges, OnDestroy, AfterContentInit {
@ContentChildren(RouterLink, { descendants: true })
links: QueryList<RouterLink>;
@ContentChildren(RouterLinkWithHref, { descendants: true })
linksWithHrefs: QueryList<RouterLinkWithHref>;
// 保存激活样式数组
private classes: string[] = [];
// 保存激活style
private styles: { [key: string]: any };
private subscription: Subscription;
public readonly isActive: boolean = false;
@Input() routerLinkActiveOptions: { exact: boolean } = { exact: false };
constructor(
private router: Router,
private element: ElementRef,
private renderer: Renderer2,
private cdr: ChangeDetectorRef
) {
this.subscription = router.events.subscribe((s: RouterEvent) => {
if (s instanceof NavigationEnd) {
this.update();
}
});
}
ngAfterContentInit(): void {
this.links.changes.subscribe(_ => this.update());
this.linksWithHrefs.changes.subscribe(_ => this.update());
this.update();
}
// 设置样式激活数组
@Input()
set routerLinkActiveClass(data: string[] | string) {
const classes = Array.isArray(data) ? data : data.split(' ');
this.classes = classes.filter(c => !!c);
}
// 设置激活style
@Input()
set routerLinkActiveStyle(data: { [key: string]: any }) {
this.styles = data;
}
ngOnChanges(changes: SimpleChanges): void {
this.update();
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
private update(): void {
if (!this.links || !this.linksWithHrefs || !this.router.navigated) return;
Promise.resolve().then(() => {
const hasActiveLinks = this.hasActiveLinks();
if (this.isActive !== hasActiveLinks) {
(this as any).isActive = hasActiveLinks;
if (hasActiveLinks) {
Object.keys(this.styles).map(res => {
this.renderer.setStyle(
this.element.nativeElement,
res,
this.styles[res]
);
});
} else {
Object.keys(this.styles).map(res => {
this.renderer.removeStyle(this.element.nativeElement, res);
});
}
this.classes.forEach(c => {
// 生效
if (hasActiveLinks) {
this.renderer.addClass(this.element.nativeElement, c);
} else {
this.renderer.removeClass(this.element.nativeElement, c);
}
});
}
});
}
private isLinkActive(
router: Router
): (link: RouterLink | RouterLinkWithHref) => boolean {
return (link: RouterLink | RouterLinkWithHref) =>
router.isActive(link.urlTree, this.routerLinkActiveOptions.exact);
}
private hasActiveLinks(): boolean {
return (
this.links.some(this.isLinkActive(this.router)) ||
this.linksWithHrefs.some(this.isLinkActive(this.router))
);
}
}
复制代码
测试使用
<div class="tab-item" [routerLink]="item.pagePath" [routerLinkActiveClass]="activeClass" [routerLinkActiveStyle]="activeStyle" *ngFor="let item of items">
<p>{{item.text}}</p>
</div>
复制代码
activeStyle = {
color: this.cfg.selectedColor
}
activeClass = 'active';
复制代码