Несколько ключевых слушателей с RxJS - PullRequest
1 голос
/ 04 марта 2020

У меня есть физический движок, который обновляется с каждым кадром, и у меня есть автомобиль с колесами, которым я хотел бы управлять с помощью клавиш со стрелками.

В качестве метода грубой силы я создал 4 Listeners, по одному для каждой клавиши со стрелкой, например:

при нажатии клавиши ...

    fromEvent(document, KEY_DOWN)
          .pipe(
            filter(e => e.keyCode === KEYS.UP),
            filter(e => !e.repeat)
          )
          .subscribe(() => {
            ...
            updateSpeed(...)
          });

и когда ключ отпущен ...

 fromEvent(document, KEY_UP)
      .pipe(filter(e => e.keyCode === KEYS.UP))
      .subscribe(() => {
        ...
      updateSpeed(...) // set speed back to 0
      });

Это работает, но выглядит утомительно, поскольку мне нужно создать слушателя keydown и слушателя keyup для каждого ключа (всего 8 слушателей). Есть ли способ объединить события, иметь один и более элегантный контроллер?

1 Ответ

1 голос
/ 04 марта 2020

Да, вам следует обратиться к combineLatest или одному из операторов комбинации (https://scotch.io/tutorials/rxjs-operators-for-dummies-forkjoin-zip-combinelatest-withlatestfrom).

Это не полный ответ, а то, с чего можно начать

import { combineLatest } from 'rxjs';
...
x = combineLatest(
  fromEvent(document, KEY_DOWN).pipe(
    filter(e => e.keyCode === KEYS.UP || /* Allow the other 3 keys with or statements */),
    filter(e => !e.repeat),
    startWith(null),
  ),
  fromEvent(document, KEY_UP).pipe(
    filter(e => e.keyCode === KEYS.UP || /* Allow the other 3 keys with or statements */)),
    startWith(null),
  )
).subscribe(([keyDown, keyUp]) => {
    // you have access to keyDown and keyUp events here. Make sure they are truthy since we startWith null and see their values and do the appropriate actions
  });

....
x.unsubscribe();

I startWith null, поскольку combineLatest, каждая наблюдаемая должна излучать хотя бы один раз, чтобы поток запустился, чтобы запустить поток. Возможно, вам придется поиграть, чтобы получить желаемые результаты.

Кроме того, поскольку вы подписываетесь на events, для вас очень важно unsubscribe из подписки, потому что события не являются конечными, и это может привести к непредсказуемому поведению (подписка реагирует на каждую кнопку ключа, даже если этот код не «живой»).

==================== ======= Редактировать ====================== Я думаю, merge - это даже лучший способ.

import { merge } from 'rxjs';

x = merge(
  fromEvent(document, KEY_DOWN).pipe(
    filter(e => e.keyCode === KEYS.UP || /* Allow the other 3 keys with or statements */),
    filter(e => !e.repeat),
  ),
  fromEvent(document, KEY_UP).pipe(
    filter(e => e.keyCode === KEYS.UP || /* Allow the other 3 keys with or statements */)),
  )
).subscribe(keyUpOrKeyDown => {
  // now you have a handle on the event and can do the appropriate action accordingly
});
....
x.unsubscribe();

Таким образом, я считаю, что лучше, так как вам не нужно startWith(null)

...