Angular 5实现点击链接变色并重置其他链接默认样式
Angular 5指令实现导航链接点击激活并重置其他链接状态
我来帮你搞定这个需求!你想用Angular 5指令实现:点击Materialize导航里的链接时改变文字颜色,且只有当前点击的链接保持高亮,其他所有链接(包括之前点击过的)都恢复默认颜色。
先看看你现有的代码:
导航HTML结构
<ul id="slide-out" class="side-nav fixed"> <li> <a class="link-text-1" appHighlight> <span>Parent-alone</span> </a> </li> <li> <a class="link-text-2" appHighlight> <span>Parent</span> </a> <ul id="inner" class="inner"> <li> <a class="child-link-1" appHighlight> <span>Child-1</span> </a> </li> <li> <a class="child-link-2" appHighlight> <span>Child-2</span> </a> </li> </ul> </li> </ul>
现有指令代码
import {Directive, ElementRef, HostListener} from '@angular/core'; @Directive({ selector: '[appHighlight]' }) export class HighlightDirective { constructor(private el: ElementRef) { } @HostListener('click') clickedLink() { this.highlight('red'); } private highlight(color: string) { this.el.nativeElement.style.color = color; } }
问题分析
你当前的指令只能单独控制自己绑定的元素,各个指令实例之间没有通信机制。所以当点击新链接时,旧的高亮链接不会自动恢复默认颜色——这就是核心问题。
解决方案:用共享服务实现指令间通信
我们需要一个共享服务来协调所有appHighlight指令的状态:当某个链接被点击时,通过服务通知所有指令,让非当前点击的链接重置样式。
步骤1:创建共享服务
这个服务负责触发激活事件,让所有指令监听并响应状态变化:
import { Injectable, EventEmitter } from '@angular/core'; @Injectable() export class HighlightService { // 定义事件发射器,传递当前激活的元素 linkActivated = new EventEmitter<HTMLElement>(); }
步骤2:修改HighlightDirective
注入共享服务,实现点击时高亮自身,并通知其他指令重置:
import { Directive, ElementRef, HostListener, OnInit, OnDestroy } from '@angular/core'; import { HighlightService } from './highlight.service'; import { Subscription } from 'rxjs'; @Directive({ selector: '[appHighlight]' }) export class HighlightDirective implements OnInit, OnDestroy { // 保存元素的默认文字颜色 private defaultColor: string; // 保存订阅对象,防止内存泄漏 private subscription: Subscription; constructor( private el: ElementRef, private highlightService: HighlightService ) {} ngOnInit() { // 获取元素初始的默认颜色(从计算样式中读取) this.defaultColor = getComputedStyle(this.el.nativeElement).color; // 订阅服务的激活事件:如果当前元素不是激活元素,就重置颜色 this.subscription = this.highlightService.linkActivated.subscribe(activeEl => { if (activeEl !== this.el.nativeElement) { this.el.nativeElement.style.color = this.defaultColor; } }); } @HostListener('click') clickedLink() { // 高亮当前链接 this.highlight('red'); // 通知服务:当前元素被激活 this.highlightService.linkActivated.emit(this.el.nativeElement); } private highlight(color: string) { this.el.nativeElement.style.color = color; } ngOnDestroy() { // 组件销毁时取消订阅,避免内存泄漏 if (this.subscription) { this.subscription.unsubscribe(); } } }
步骤3:在模块中注册服务和指令
确保在你的Angular模块中提供这个服务,比如AppModule或者相关的功能模块:
import { NgModule } from '@angular/core'; import { HighlightDirective } from './highlight.directive'; import { HighlightService } from './highlight.service'; @NgModule({ declarations: [HighlightDirective], providers: [HighlightService], exports: [HighlightDirective] }) export class HighlightModule {}
进阶优化:用CSS类控制样式(推荐)
直接操作style不够灵活,更推荐用CSS类来管理样式,这样样式和逻辑分离,维护更方便:
- 先在CSS中定义默认样式和激活样式:
/* 默认链接颜色 */ .link-text-1, .link-text-2, .child-link-1, .child-link-2 { color: #333; /* 替换成你的默认颜色 */ } /* 激活状态样式 */ .active-link { color: red !important; }
- 修改指令,用类来替换直接操作style:
import { Directive, ElementRef, HostListener, OnInit, OnDestroy } from '@angular/core'; import { HighlightService } from './highlight.service'; import { Subscription } from 'rxjs'; @Directive({ selector: '[appHighlight]' }) export class HighlightDirective implements OnInit, OnDestroy { private subscription: Subscription; constructor( private el: ElementRef, private highlightService: HighlightService ) {} ngOnInit() { this.subscription = this.highlightService.linkActivated.subscribe(activeEl => { if (activeEl !== this.el.nativeElement) { this.el.nativeElement.classList.remove('active-link'); } }); } @HostListener('click') clickedLink() { // 给当前元素添加激活类 this.el.nativeElement.classList.add('active-link'); // 通知服务激活事件 this.highlightService.linkActivated.emit(this.el.nativeElement); } ngOnDestroy() { if (this.subscription) { this.subscription.unsubscribe(); } } }
这样实现后,每次点击任意带appHighlight指令的链接,都会自动高亮当前链接,同时把其他所有链接的激活状态移除,完美满足你的需求!
内容的提问来源于stack exchange,提问作者Dariusz Mozgowoj
相关产品推荐
相关产品推荐

