Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
6
Help us understand the problem. What is going on with this article?
@daikiojm

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

More than 3 years have passed since last update.

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

6
Help us understand the problem. What is going on with this article?
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
daikiojm
https://daikiojm.me/

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
6
Help us understand the problem. What is going on with this article?