如何使用RxJs改造组件实现防重复点击动画控制
用RxJS实现Angular组件防重复点击动画控制
核心思路
利用RxJS的exhaustMap操作符处理点击流,确保只有当上一次动画完成后,才会响应下一次点击。这种方式无需手动维护isChildAnimationComplete状态,完全通过响应式流控制逻辑。
改造步骤
1. 父组件(MeetingObjectComponent)修改
导入必要的RxJS工具和操作符,用Subject捕获点击事件,结合子组件的动画完成信号构建响应式流:
import { Component, Input, ViewChild, OnInit, OnDestroy } from '@angular/core'; import { Meeting } from './path-to-meeting-type'; import { Subject, exhaustMap, take, tap, startWith, Subscription } from 'rxjs'; import { ChatComponent } from './chat.component'; @Component({ selector: 'app-meeting-object', templateUrl: './meeting-object.component.html', styleUrls: ['./meeting-object.component.css'], animations: [ trigger('highlightDim', [...]) ] }) export class MeetingObjectComponent implements OnInit, OnDestroy { @Input() public meetingData: Meeting | undefined; @ViewChild(ChatComponent) chatComponent!: ChatComponent; public isExpanded: boolean = false; private click$ = new Subject<void>(); private subscription?: Subscription; ngOnInit(): void { // 将子组件的动画完成事件转成Observable,初始状态允许点击 const animationComplete$ = this.chatComponent.animationComplete.pipe( startWith(null) ); // 用exhaustMap忽略动画未完成时的重复点击 this.subscription = this.click$.pipe( exhaustMap(() => animationComplete$.pipe( take(1), // 仅取一次动画完成信号 tap(() => { this.isExpanded = !this.isExpanded; }) )) ).subscribe(); } ngOnDestroy(): void { // 清理订阅避免内存泄漏 this.subscription?.unsubscribe(); this.click$.complete(); } }
2. 父组件模板修改
将原来的(click)="expand()"替换为触发Subject的next()方法:
<div class="meeting" (click)="click$.next()" [@highlightDim]="isExpanded"> </div> <app-chat [isExpanded]="isExpanded" (animationComplete)="$event" ></app-chat>
3. 子组件(ChatComponent)保持不变
子组件无需修改,继续通过animationComplete事件发送动画完成信号:
@Component({ selector: 'app-chat', templateUrl: './chat.component.html', styleUrls: ['./chat.component.css'], animations:[trigger('openClose', [...])] }) export class ChatComponent { @Input() isExpanded: boolean | undefined; @Output() animationComplete = new EventEmitter<null>(); }
关键逻辑说明
exhaustMap操作符:当内部Observable(等待动画完成的流)未完成时,会忽略所有新的点击事件,彻底解决重复点击触发多次动画的问题。startWith(null):确保组件初始化时允许第一次点击,因为此时还没有任何动画完成信号。- 订阅清理:组件销毁时取消订阅并完成
Subject,避免内存泄漏。
内容的提问来源于stack exchange,提问作者JackFord
相关产品推荐
相关产品推荐

