LoginSignup
4
8

More than 5 years have passed since last update.

RxJSでいろいろなパターンのクリックイベントを取得する

Posted at

RxJSのストリームの扱いに慣れるためにいろいろ試してみたメモ。
サンプルコードではインポートの記述を省略しているので、実際の動きはstackblitzで確認するといいかもです。

基本編

fromEventを使って、プリミティブなクリックイベントを取得してみます。

次のようなHTMLを用意します。

index.html
<button id="button">押してね</button>

fromEventの第一引数に対象のHTMLElementを第二引数にイベント名を入力します。

index.ts
const button: HTMLElement = document.getElementById('button');

// click
const click$: Observable<Event> = fromEvent(button, 'click');
// mousedown
const mousedown$: Observable<Event> = fromEvent(button, 'mousedown');
// mouseup
const mouseup$: Observable<Event> = fromEvent(button, 'mouseup');

それぞれのイベントストリームは、pipe()してゴニョゴニョするなりsubscribeするなり好きに扱う事ができるようになります。

ダブルクリック

まず、基本編同様にfromEventdblclickイベントをハンドリングする方法があります。

index.ts
const button: HTMLElement = document.getElementById('button');

// dblclick
const dblclick$: Observable<Event> = fromEvent(button, 'dblclick');

別の方法として、次のようにハンドリングする用法も考えられます。
(ダブルクリックの間隔をアプリケーション側で調整したい場合など?)

index.ts
const button: HTMLElement = document.getElementById('button');

const click$: Observable<Event> = fromEvent(button, 'click');

const dblclick$ = click$.pipe(
  bufferTime(1000),
  map((event: Event[]) => event.length),
  filter((eventLength: number) => eventLength === 2),
);

bufferTimeで一定期間のイベントストリームをまとめて流し、そのイベント数をフィルターして条件にあったクリックイベントのみを取得しています。

n秒間にx回クリック

これは、ダブルクリックの2つめとほぼ同じですが、次のように実現できますね。

index.ts
const button: HTMLElement = document.getElementById('button');

const click$: Observable<Event> = fromEvent(button, 'click');

// 5 times in 2 seconds
const dblclick$ = click$.pipe(
  bufferTime(2000),
  map((event: Event[]) => event.length),
  filter((eventLength: number) => eventLength === 5),
);

長押し

index.ts
const button: HTMLElement = document.getElementById('button');

const mouseDown$: Observable<MouseEvent> = fromEvent(button, 'mousedown');
const mouseUp$: Observable<MouseEvent> = fromEvent(button, 'mouseup');

// long press 2 seconds
const longpress$ = mouseDown$.pipe(
  mergeMap((e) => {
    return of(e).pipe(
      delay(2000),
      takeUntil(mouseUp$),
    );
  }),
);

ポイントは、subscribeをキャンセルする条件(takeUntil)をmergeMapで返す内側のObservableに対して設定することです。
これを、外側(全体)のObservableに対して設定してしまうと、このイベントが一回発火した以降、再度発火しなくなってしまいます。

 終わりに

RxJS楽しいです(小並感)。
これ何に使うの感は若干ありますが、上記で紹介したストリームをいい感じに組み合わせて複雑なパターンを作り、「隠しページへのリンクを配置する」などといった使い方ができるのではないでしょうか。

4
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
8