关于 RxJS 中间隔的一个简单问题 - 我制作了一个轮播,其中幻灯片每分钟都会变化,并且有一个细节令我不满意。当用户手动将幻灯片切换到下一张或上一张时,interval 仍会自动更改幻灯片,但无论何时,直到interval 触发新值为止,它都会忽略用户所做的任何操作。如何让间隔知道用户是否更改了幻灯片,并且仅根据用户操作计算一分钟,然后自动更改幻灯片。其他时间间隔应自动正常工作。
很高兴听到想法,谢谢!!!
这是我得到的:
source = interval(10000);
ngOnInit(): void {
this.source.subscribe(() => this.slide('forward'));
}
slide(option): void {
switch (option) {
case 'forward':
this.currentSlide === this.SLIDES.length - 1 ?
this.currentSlide = DEFAULT_SLIDE : this.currentSlide++;
break;
case 'back':
this.currentSlide === DEFAULT_SLIDE ?
this.currentSlide = this.SLIDES.length - 1 : this.currentSlide--;
break;
}
}
模板:
<div class="sliderNav">
<mat-icon (click)="slide('back')">keyboard_arrow_up</mat-icon>
<p>{{currentSlide + 1}}/{{SLIDES.length}}</p>
<mat-icon (click)="slide('forward')">keyboard_arrow_down</mat-icon>
</div>
最佳答案
我想说 RxJS 对于这种行为来说有点过分了。它可以使用普通 JS 来实现 setTimeout()
功能。此外,当组件被销毁时,您不会关闭订阅,这可能会导致内存泄漏。
方案一:JS setTimeout()
timeoutId: number;
ngOnInit(): void {
this.resetTimer(); // <-- start timer when the component is created
}
resetTimer() {
if (!!this.timeoutId) { // <-- Update: clear the timeout
clearTimeout(this.timeoutId);
}
this.timeoutId = setTimeout(() => this.slide('forward'), 10000);
}
/**
* Reset the timer each time `slide()` function is triggered:
* 1. When the `setTimeout()` triggers the callback
* 2. When the user changes the slide manually
*/
slide(option): void {
this.resetTimer(); // <-- reset timer here
switch (option) {
case 'forward':
this.currentSlide === this.SLIDES.length - 1 ?
this.currentSlide = DEFAULT_SLIDE : this.currentSlide++;
break;
case 'back':
this.currentSlide === DEFAULT_SLIDE ?
this.currentSlide = this.SLIDES.length - 1 : this.currentSlide--;
break;
}
}
ngOnDestroy() {
clearTimeout(this.timeoutId); // <-- clear the timeout when the component is destroyed
}
选项2:RxJS interval()
如果你坚持使用 RxJS,你需要注意很多事情
- 使用诸如
ReplaySubject
(此处所示)之类的多播可观察对象或使用带有fromEvent
函数的模板引用变量(未显示)来获取用户的手动输入. - 使用
switchMap
运算符将一个可观察量映射到另一个可观察量。当外部可观察对象发出时,switchMap 取消/关闭内部可观察对象。这样计时器就会重新生成。 - 在
ngOnDestroy()
Hook 中关闭订阅,以避免打开的订阅造成内存泄漏。此处使用takeUntil
运算符进行说明。
Controller (*.ts)
import { ReplaySubject } from 'rxjs';
import { map, switchMap, takeUntil } from 'rxjs/operators';
clickEvents$ = new ReplaySubject<string>(1); // <-- buffer 1
closed$ = new ReplaySubject<any>(1);
ngOnInit() {
this.clickEvents$.asObservable.pipe(
switchMap((event: string) => interval(10000).pipe( // <-- cancel inner subscription when outer subscription emits
map(() => event) // <-- map back to the event
)),
takeUntil(this.closed$)
).subscribe(this.slide.bind(this)); // <-- use `bind()` to preserve `this` in callback
}
slide(option): void {
switch (option) {
case 'forward':
this.currentSlide === this.SLIDES.length - 1 ?
this.currentSlide = DEFAULT_SLIDE : this.currentSlide++;
break;
case 'back':
this.currentSlide === DEFAULT_SLIDE ?
this.currentSlide = this.SLIDES.length - 1 : this.currentSlide--;
break;
}
}
ngOnDestroy() {
this.closed$.next(); // <-- close open subscriptions
}
模板(*.html)
<button (click)="clickEvent$.next('back')">Back</button>
<button (click)="clickEvent$.next('forward')">Forward</button>
关于javascript - 在 Angular 中单击时重置 rxjs 间隔,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68174823/