查看費德里科的答案,下面是一個更優雅和習慣解決方案。
可避免重複項目從可觀察到的(正如你看到的,當某個鍵)與distinctUntilChanged
過濾掉匹配最後發出的值(其中匹配由發射值或它們的值相等確定的值由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,DI在控制檯中執行以下操作:
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
注 「的keydown 68」(d)的重複時釋放A和S.這是因爲事件僅針對最近按下的鍵重複。使用類似的想法告訴了一個在您的評論中,我們可以改爲嘗試一個自定義過濾器,維護着這個鍵被按下列表:
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,然後釋放, 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風格。 (任何意見讚賞。)
我不明白你想過濾。重複密碼是什麼意思?你是否想把鑰匙與鑰匙相提並論? – paulpdaniels
當你按下一個鍵並按住它時,通常你會得到重複,很多keydowns。當按鍵被按下時,我想要1'按'事件,並且當按鍵被釋放時,'1'釋放'事件。對不起,我的英語 –
而且,是的,需要匹配鍵盤和keydowns之間的匹配 –