我需要在不重复的情况下获得干净的keydown / keyup事件。当你按下一个键keydown事件发生时,当你释放 - keyup。没有混乱的重复keydowns。
此处的代码:
template
如何使其适应这项工作?
答案 0 :(得分:16)
虽然它很好用但是icio与状态跟踪的解决方案非常不合时宜。适当的RxJs 5解决方案是:
var keyDowns = Rx.Observable.fromEvent(document, "keydown")
var keyUps = Rx.Observable.fromEvent(document, "keyup")
var keyPresses = keyDowns
.merge(keyUps)
.groupBy(e => e.keyCode)
.map(group => group.distinctUntilChanged(null, e => e.type))
.mergeAll()
说明:
答案 1 :(得分:7)
查看Federico的答案,以获得更优雅和惯用的解决方案。
您可以使用distinctUntilChanged
来避免来自可观察对象的重复项目(如您所持有的那样),该http://plnkr.co/edit/ishIqko1GHT7IGvXV8ZF?p=preview过滤掉与最后一个发射值匹配的值(其中匹配由发射值的相等性或其变换值决定通过keySelector
回调参数)。
在您的情况下,这可能看起来像:
var keyDowns = Rx.Observable.fromEvent(document, 'keydown');
var keyUps = Rx.Observable.fromEvent(document, 'keyup');
var keyActions = Rx.Observable
.merge(keyDowns, keyUps)
.distinctUntilChanged(function(e) { return e.type + (e.key || e.which); });
keyActions.subscribe(function(e) {
console.log(e.type, e.key || e.which, e.keyIdentifier);
});
但是当持有多个键时,这会失败。在Chrome OS X中,如果我按住A,S,D,然后释放A,S,D,我会在控制台中获得以下内容:
keydown 65 U+0041
keydown 83 U+0053
keydown 68 U+0044
keyup 65 U+0041
keydown 68 U+0044
keyup 83 U+0053
keydown 68 U+0044
keyup 68 U+0044
注意释放A和S时重复“keydown 68”(D)。这是因为keydown
事件仅针对最近按下的键重复。使用与评论中的想法类似的想法,我们可以尝试使用自定义过滤器来维护已按下哪些键的列表:
var keyDowns = Rx.Observable.fromEvent(document, 'keydown');
var keyUps = Rx.Observable.fromEvent(document, 'keyup');
var keyActions = Rx.Observable
.merge(keyDowns, keyUps)
.filter((function() {
var keysPressed = {};
return function(e) {
var k = e.key || e.which;
if (e.type == 'keyup') {
delete keysPressed[k];
return true;
} else if (e.type == 'keydown') {
if (keysPressed[k]) {
return false;
} else {
keysPressed[k] = true;
return true;
}
}
};
})());
keyActions.subscribe(function(e) {
console.log(e.type, e.key || e.which, e.keyIdentifier);
});
按住A,S,D,然后释放A,S,D,现在给出:
keydown 65 U+0041
keydown 83 U+0053
keydown 68 U+0044
keyup 65 U+0041
keyup 83 U+0053
keyup 68 U+0044
这与您在评论中提到的方法类似,只是我们正在过滤组合流而不是预过滤,以便组合流看起来像我们喜欢的那样。
我对rx.js的经验不足以断言这是最好的方法,但它确实感觉更符合Rx风格。 (任何评论都赞赏。)
答案 2 :(得分:1)
在RxJs 5中,如果您只想过滤单个键,它将是:
import { fromEvent } from 'rxjs/observable/fromEvent';
import { merge } from 'rxjs/operators/merge';
import { distinctUntilChanged, filter } from 'rxjs/operators';
const keyDowns = fromEvent(document, 'keydown');
const keyUps = fromEvent(document, 'keyup');
const keyPresses = keyDowns.pipe(
merge(keyUps),
filter((e: KeyboardEvent) => e.keyCode === 17),
distinctUntilChanged((x, y) => x.type == y.type)
);
keyPresses.subscribe((ctrlpress) => {
this.holdingCtrl = ctrlpress.type === 'keydown';
});