这是我的代码:
app.component.ts
notifier$ = new BehaviorSubject<any>({});
notify() {
this.notifier$.next({});
}
app.component.html
<div (scroll)="notify()"></div>
<child-component [inp]="notifier$ | async" />
问题是,当用户滚动时,notify()
函数被重复调用,而我每次只想调用 notify()
一次 用户开始滚动。
我可以通过这种方式完成我想要的:
scrolling = false;
scrollingTimer: NodeJS.Timer;
notify() {
clearTimeout(this.scrollingTimer);
if (!this.scrolling) {
this.notifier$.next({});
}
this.scrolling = true;
this.scrollingTimer = setTimeout(() => (this.scrolling = false), 1000);
}
但我喜欢用rxjs
来做这件事。但是 debounceTime
与我想要的相反,throttleTime
和 auditTime
都不是我想要的。有办法做到这一点吗?
最佳答案
您可以像这样构建一个可观察对象:
const scroll$ = fromEvent(document, 'scroll');
const scrollEnd$ = scroll$.pipe(
switchMapTo(
timer(1000) // on every scroll, restart a timer
)
);
const scrollStart$ = scrollEnd$.pipe( // the scroll end event triggers switch to scroll$
startWith(0), // but start it off
switchMapTo(
scroll$.pipe( // then just take the first scroll$ event
first()
)
)
);
scrollStart$.subscribe(v => console.log('scroll start'));
您可以将其概括为运算符:
function firstTimeout(timeout: number) { // welcoming notes on a better name
return input$ => {
const inputTimeout$ = input$.pipe(
switchMapTo(timer(timeout))
);
return inputTimeout$.pipe(
startWith(0),
switchMapTo(input$.pipe(first()))
);
};
}
并像这样使用它:
notifier$.pipe(firstTimeout(1000)).subscribe(v => console.log('took one'));
对于这种情况,一个好主意可能是将它包装在一个易于重用的指令中:
@Directive({
selector: '[scrollStart]'
})
export class ScrollStartDirective {
private scrollSource = new Subject();
@HostListener('scroll', ['$event'])
private onScroll(event) {
this.scrollSource.next(event);
}
@Output()
scrollStart = new EventEmitter();
constructor() {
this.scrollSource.pipe(firstTimeout(1000)).subscribe(this.scrollStart);
}
}
然后你可以像这样使用它:
<div (scrollStart)="notify()"></div>
关于javascript - 发出第一个值然后忽略计时器内发出的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57101077/