取消使用“ fromEvent”创建的可观察对象并切换到新的对象

时间:2019-06-13 06:38:07

标签: rxjs

我的目标是在1秒钟的间隔内发出“ hi hi”(直到再次发出声音),直到按键被按下为止,并在每次单击鼠标时继续发出声音。 这是我的代码:

import { of, fromEvent, interval } from 'rxjs'; 
import { map, tap, takeUntil,take, repeatWhen, shareReplay, switchMap , takeLast} from 'rxjs/operators';

const fromKeyUp$ = fromEvent(window, 'keyup').pipe(tap(_=> console.log('keyup')));

const fromMouseUp$ = fromEvent(window, 'mouseup').pipe(tap(_=> console.log('mouseup')));

const source = interval(1000).pipe(tap(_ => {
  console.log('hi again');
}), takeUntil(fromKeyUp$), repeatWhen(() => fromMouseUp$));

source.subscribe();

问题在于,当鼠标单击次数过多时,=>“ hihi”发出的次数比平时多。

我尝试使用switchMap来取消以前的mouseup提示,例如:

const fromMouseUp$ = fromEvent(window, 'mouseup').pipe(switchMap(() => tap(_=> console.log('mouseup'))));

但是它不起作用,因为Tap并非用于创建。

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

我认为您可以对运算符重新排序并使用switchMap来取消先前的interval

fromMouseUp$.pipe(
  startWith(null),
  switchMap(() => interval(1000).pipe(
    takeUntil(fromKeyUp$),
  )),
).subscribe();

答案 1 :(得分:1)

下面的代码将通过mouseup切换值或通过keyup停止值,您可以将处理逻辑放入mergeMap

const fromKeyUp$ = fromEvent(window, 'keyup').pipe(tap(_=> console.log('keyup')),mapTo(false));

const fromMouseUp$ = fromEvent(window, 'mouseup').pipe(tap(_=> console.log('mouseup')),mapTo(true));

const timeInterval=interval(1000).pipe(
  tap(_ => {
  console.log('hi again');
}))

const source=combineLatest(timeInterval,merge(fromMouseUp$,fromKeyUp$).pipe(startWith(true))
).pipe(
   mergeMap(([value,through])=>through? 
     of(value):never()),distinctUntilChanged() 
 )

source.subscribe(console.log);

使用windowToggle

的另一个更简单的选择
interval(2000).pipe(
  windowToggle(fromMouseUp$.pipe(startWith(true)),()=>fromKeyUp$),
  switchMap(obs=>obs)
).subscribe(console.log)

两种解决方案都不会中断源间隔

答案 2 :(得分:0)

使用switchMappauseresume事件的合并流中切换到所需的源。

import { interval, fromEvent, merge, EMPTY } from 'rxjs';
import { switchMap, startWith, mapTo, tap } from 'rxjs/operators';

const source$ = interval(1000).pipe(tap(_ => console.log('Hi again')));

const pause$ = fromEvent(window, 'keyup').pipe(
  tap(_ => console.log('keyup')),
  mapTo(false)
);
const resume$ = fromEvent(window, 'mouseup').pipe(
  tap(_ => console.log('mouseup')),
  mapTo(true)
);

const notification$ = merge(pause$, resume$).pipe(
  // add startWith(true) if the source should start emitting on subscribe, 
  // remove it if the source should only start on 'mouseup'
  startWith(true), 
  switchMap(val => (val ? source$ : EMPTY)),
)

notification$.subscribe();

https://stackblitz.com/edit/typescript-4zgnbn