如何在 RxJS 中创建切换流?
How to create a toggle stream in RxJS?
我想创建一个基于 keyup
和 keydown
切换的 Steam。键码在 keydown
事件中发出一次,并在 keyup
事件中再次发出。我使用 distinctUntilChanged
来防止在 keydown
触发时发送多个键码。我的代码的问题是,由于 distinctUntilChanged
.
,我无法在同一键代码上连续执行 keydown
和 keyup
目前,按下并释放 'a' 后跟 'b' 有效,但 'a' 后跟 'a' 无效。
要求
我要实现的是:
- 当按键按下时,执行一些任务
- 当按键启动时,停止执行该任务
- 多个键可以按下或向上(所以不能使用
keypress
事件)
- 不同的动作与不同的键相关联(想想 'a' 对应动作 1,'b' 对应动作 2)
代码
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);
});
我想创建一个基于 keyup
和 keydown
切换的 Steam。键码在 keydown
事件中发出一次,并在 keyup
事件中再次发出。我使用 distinctUntilChanged
来防止在 keydown
触发时发送多个键码。我的代码的问题是,由于 distinctUntilChanged
.
keydown
和 keyup
目前,按下并释放 'a' 后跟 'b' 有效,但 'a' 后跟 'a' 无效。
要求
我要实现的是:
- 当按键按下时,执行一些任务
- 当按键启动时,停止执行该任务
- 多个键可以按下或向上(所以不能使用
keypress
事件) - 不同的动作与不同的键相关联(想想 'a' 对应动作 1,'b' 对应动作 2)
代码
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);
});