如何在 RxJS 中创建切换流?

How to create a toggle stream in RxJS?

我想创建一个基于 keyupkeydown 切换的 Steam。键码在 keydown 事件中发出一次,并在 keyup 事件中再次发出。我使用 distinctUntilChanged 来防止在 keydown 触发时发送多个键码。我的代码的问题是,由于 distinctUntilChanged.

,我无法在同一键代码上连续执行 keydownkeyup

目前,按下并释放 'a' 后跟 'b' 有效,但 'a' 后跟 'a' 无效。

要求

我要实现的是:

代码

var getKeyCode = function(e) { return e.which; }
var target = document.querySelector('body');

var keyDownStream = Rx.Observable.fromEvent(target, 'keydown')
    .distinctUntilChanged(getKeyCode);

var keyUpStream = Rx.Observable.fromEvent(target, 'keyup')
    .distinctUntilChanged(getKeyCode);

var toggleStream = Rx.Observable.merge(keyDownStream, keyUpStream);

toggleStream.subscribe(function(e) {
    console.log(e.which);
});

我用过:

var toggleStream = Rx.Observable.fromEvent(document.body, 'keydown').filter(function ( e, index ) {
  return index < 1;
}).takeUntil(Rx.Observable.fromEvent(document.body, 'keyup')).repeat();

toggleStream.subscribe(function ( e ) {
 // the task should go here 
 console.log("key down :" + e.which);
});

你可以在这里找到一个 jsbin : http://jsbin.com/xuqasawese/edit?html,js,console,output

目前,按下并释放 'a' 后跟 'b' 有效,'a' 后跟 'a' 也有效。但是,您可以想象按下键 'a' 并且没有释放该键,按下另一个键 'b' 并释放 'b'。然后按另一个键'c',你的动作就会被执行。这是一种边缘情况,但如果发生这种情况,您是否有任何预期的行为?

发现解决方案是将 distinctUntilChanged 移动到合并的可观察对象并按事件类型和键码进行过滤。这将确保订阅者在 keydown 事件和 keyup 事件中收到一次相同密钥的通知。

var filterByTypeAndKeyCode = function(e) { return e.type + e.which; }
var target = document.querySelector('body');
var keyUpStream = Rx.Observable.fromEvent(target, 'keyup');
var keyDownStream = Rx.Observable.fromEvent(target, 'keydown');

Rx.Observable.merge(keyDownStream, keyUpStream)
    .distinctUntilChanged(filterByTypeAndKeyCode)
    .subscribe(function(e) {
        console.log(e.which);
    });