8
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

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

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
8
Help us understand the problem. What are the problem?