イベント

イベントは、要素が変更を伝える標準的な方法です。これらの変更は通常、ユーザー操作によって発生します。たとえば、ボタンはユーザーがクリックしたときにクリックイベントをディスパッチし、入力はユーザーが入力値を入力したときに変更イベントをディスパッチします。

これらの自動的にディスパッチされる標準イベントに加えて、Lit 要素はカスタムイベントをディスパッチできます。たとえば、メニュー要素は選択されたアイテムが変更されたことを示すイベントをディスパッチし、ポップアップ要素はポップアップが開いたり閉じたりしたときにイベントをディスパッチする場合があります。

Lit 要素自体を含む任意の Javascript コードは、イベントをリスニングし、イベントに基づいてアクションを実行できます。たとえば、ツールバー要素はメニューアイテムが選択されたときにリストをフィルタリングし、ログイン要素はログインボタンのクリックを処理したときにログインを処理する場合があります。

標準の addEventListener APIに加えて、Lit はイベントリスナーを追加するための宣言的な方法を導入しています。

テンプレート内の @ 式を使用して、コンポーネントのテンプレート内の要素にイベントリスナーを追加できます。宣言的なイベントリスナーは、テンプレートがレンダリングされるときに追加されます。

宣言的なイベントリスナーで使用されるイベントオプション(passivecapture など)をカスタマイズする必要がある場合は、@eventOptions デコレータを使用してリスナーにこれらのオプションを指定できます。@eventOptions に渡されるオブジェクトは、addEventListeneroptions パラメータとして渡されます。

デコレータの使用。 デコレータは提案されている JavaScript 機能であるため、デコレータを使用するには、Babel や TypeScript などのコンパイラを使用する必要があります。詳細については、「デコレータの有効化」を参照してください。

デコレータを使用していない場合は、イベントリスナー式にオブジェクトを渡して、イベントリスナーオプションをカスタマイズできます。オブジェクトには handleEvent() メソッドが含まれている必要があり、addEventListener()options 引数に通常表示されるオプションを含めることができます。

コンポーネントまたはそのシャドウルートへのイベントリスナーの追加

「コンポーネントまたはそのシャドウルートへのイベントリスナーの追加」へのパーマリンク

コンポーネントのスロットされた子要素と、コンポーネントテンプレートを介してシャドウDOMにレンダリングされた子要素からディスパッチされたイベントを通知するには、標準のaddEventListener DOMメソッドを使用してコンポーネント自体にリスナーを追加できます。詳細は、MDN の EventTarget.addEventListener() を参照してください。

コンポーネントコンストラクタは、コンポーネントにイベントリスナーを追加するのに適した場所です。

コンポーネント自体にイベントリスナーを追加することは、イベントデリゲーションの一種であり、コードを削減したり、パフォーマンスを向上させたりするために実行できます。詳細は、「イベントデリゲーション」を参照してください。通常、これを行う場合、イベントの target プロパティを使用して、どの要素がイベントを発生させたかに基づいてアクションを実行します。

ただし、コンポーネントのシャドウDOMから発生したイベントは、コンポーネントのイベントリスナーによって認識されるとリターゲティングされます。つまり、イベントターゲットはコンポーネント自体になります。「Shadow DOM でのイベントの処理」で詳細情報をご覧ください。

リターゲティングはイベントデリゲーションを妨げる可能性があり、これを回避するために、イベントリスナーはコンポーネントのシャドウルート自体に追加できます。shadowRootconstructor では使用できないため、イベントリスナーは次のように createRenderRoot メソッドに追加できます。createRenderRoot メソッドからシャドウルートを返すことを確認することが重要です。

コンポーネントが自身またはそのテンプレート化されたDOM以外のもの(たとえば、WindowDocument、またはメインDOM内の要素)にイベントリスナーを追加する場合は、connectedCallback でリスナーを追加し、disconnectedCallback で削除する必要があります。

  • disconnectedCallback でイベントリスナーを削除すると、コンポーネントによって割り当てられたメモリは、コンポーネントが破棄されたり、ページから切断されたりしたときにクリーンアップされます。

  • connectedCallback(コンストラクタや firstUpdated などではなく)でイベントリスナーを追加すると、コンポーネントがDOMから切断され、その後再び接続された場合に、コンポーネントはイベントリスナーを再作成します。

カスタム要素の使用に関する MDN のドキュメントについては、「ライフサイクルコールバック」を参照してください。

イベントリスナーの追加は非常に高速であり、通常はパフォーマンス上の問題ではありません。ただし、高頻度で使用され、多くのイベントリスナーを必要とするコンポーネントの場合、イベントデリゲーション を使用して使用されるリスナーの数を減らし、レンダリング後に非同期的にリスナーを追加することで、最初のレンダリングのパフォーマンスを最適化できます。

イベントデリゲーションを使用すると、使用されるイベントリスナーの数を減らし、パフォーマンスを向上させることができます。コードを削減するために、イベント処理を集中化することも便利です。イベントデリゲーションは、バブルするイベントを処理する場合にのみ使用できます。バブリングの詳細については、「イベントのディスパッチ」を参照してください。

バブリングイベントは、DOM内の任意の祖先要素で認識できます。これを利用して、祖先コンポーネントに単一のイベントリスナーを追加し、DOM内の任意の子孫によってディスパッチされたバブリングイベントを通知できます。イベントの target プロパティを使用して、イベントをディスパッチした要素に基づいて特定のアクションを実行します。

レンダリング後にイベントリスナーを追加するには、firstUpdated メソッドを使用します。これは、コンポーネントが最初に更新されてテンプレート化されたDOMをレンダリングした後に実行されるLitライフサイクルコールバックです。

firstUpdated コールバックは、コンポーネントが最初に更新され、その render メソッドが呼び出された後(ただし、ブラウザがペイントする前に)に発生します。

詳細については、ライフサイクルドキュメントのfirstUpdated を参照してください。

リスナーがユーザーがコンポーネントを見ることができるようになった後に追加されるようにするには、ブラウザがペイントされた後に解決される Promise を待機できます。

テンプレートで宣言的な @ 構文を使用して追加されたイベントリスナーは、自動的にコンポーネントにバインドされます。

したがって、宣言的なイベントハンドラ内で this を使用して、コンポーネントインスタンスを参照できます。

addEventListener を使用してリスナーを命令的に追加する場合、this がコンポーネントを参照するように、アロー関数を使いましょう。

詳細については、MDN のthis のドキュメントを参照してください。

繰り返しテンプレートから発生したイベントのリスニング

「繰り返しテンプレートから発生したイベントのリスニング」へのパーマリンク

繰り返しアイテムのイベントをリスニングする際には、イベントがバブルする場合はイベントデリゲーション を使用するのが便利な場合があります。イベントがバブルしない場合、繰り返し要素にリスナーを追加できます。両方の方法の例を以下に示します。

@ 式に nullundefined、または何も渡すと、既存のリスナーが削除されます。

すべてのDOMノードは、dispatchEventメソッドを使用してイベントをディスパッチできます。 まず、イベントの種類とオプションを指定して、イベントインスタンスを作成します。 次に、それを以下のようにdispatchEventに渡します。

bubblesオプションを使用すると、イベントをDOMツリーを上って、ディスパッチしている要素の祖先に伝播させることができます。イベントがイベントデリゲーションに参加できるようにするには、このフラグを設定することが重要です。

composedオプションは、要素が存在するシャドウDOMツリーの上でイベントをディスパッチできるように設定するのに役立ちます。

詳細については、シャドウDOMでのイベントの処理を参照してください。

イベントのディスパッチの完全な説明については、MDNのEventTarget.dispatchEvent()を参照してください。

イベントは、ユーザーの操作またはコンポーネントの状態の非同期的な変更に応じてディスパッチする必要があります。一般的に、コンポーネントのプロパティまたは属性APIを介して所有者によって行われた状態の変化に応じてディスパッチするべきではありません。これは、ネイティブのWebプラットフォーム要素が動作する一般的な方法です。

たとえば、ユーザーがinput要素に値を入力するとchangeイベントがディスパッチされますが、コードがinputvalueプロパティを設定しても、changeイベントはディスパッチされません

同様に、メニューコンポーネントは、ユーザーがメニュー項目を選択したときにイベントをディスパッチする必要がありますが、たとえば、メニューのselectedItemプロパティが設定された場合にイベントをディスパッチするべきではありません。

これは通常、コンポーネントがリスンしている別のイベントに応じてイベントをディスパッチする必要があることを意味します。

多くの場合、イベントは要素が更新されてレンダリングされた後でのみ発生させる必要があります。これは、ユーザー操作に基づいてレンダリングされた状態の変化を伝えることを目的としたイベントの場合に必要になる可能性があります。この場合、状態を変更した後、イベントをディスパッチする前に、コンポーネントのupdateComplete Promiseをawaitできます。

イベントは、EventまたはCustomEventを構築することでディスパッチできます。どちらのアプローチも妥当です。CustomEventを使用する場合、イベントデータはイベントのdetailプロパティに渡されます。Eventを使用する場合、イベントのサブクラスを作成し、カスタムAPIをアタッチできます。

イベントの構築の詳細については、MDNのEventを参照してください。

詳細については、カスタムイベントに関するMDNのドキュメントを参照してください。

シャドウDOMを使用する場合、標準的なイベントシステムにいくつかの変更があり、理解することが重要です。シャドウDOMは主に、これらの「シャドウ」要素に関する詳細をカプセル化するDOMでのスコープメカニズムを提供するために存在します。そのため、シャドウDOM内のイベントは、外部のDOM要素から特定の詳細をカプセル化します。

デフォルトでは、シャドウルート内でディスパッチされたイベントは、そのシャドウルートの外からは見えません。イベントをシャドウDOMの境界を越えて渡すには、composedプロパティtrueに設定する必要があります。DOMツリー内のすべてのノードがイベントを見ることができるように、composedbubblesを組み合わせることが一般的です。

イベントがcomposedbubbleの場合、イベントをディスパッチする要素のすべての祖先(外部のシャドウルート内の祖先を含む)で受信できます。イベントがcomposedであるがbubbleでない場合、イベントをディスパッチする要素と、シャドウルートを含むホスト要素でのみ受信できます。

すべてのマウス、タッチ、キーボードイベントを含む、ほとんどの標準的なユーザーインターフェースイベントは、バブリングと合成の両方です。合成イベントに関するMDNのドキュメントで詳細を確認してください。

合成イベントは、シャドウルート内からディスパッチされるとリターゲティングされます。つまり、シャドウルートまたはその祖先のいずれかをホストする要素のリスナーに対しては、ホスト要素から来たように見えます。Litコンポーネントはシャドウルートにレンダリングされるため、Litコンポーネント内からディスパッチされたすべての合成イベントは、Litコンポーネント自体によってディスパッチされたように見えます。イベントのtargetプロパティはLitコンポーネントです。

高度なケースでイベントの起源を特定する必要がある場合は、event.composedPath() APIを使用します。このメソッドは、シャドウルート内のノードを含む、イベントディスパッチによってトラバースされたすべてのノードの配列を返します。これはカプセル化を破るため、公開される可能性のある実装の詳細に依存しないように注意する必要があります。一般的なユースケースには、クライアントサイドルーティングのために、クリックされた要素がアンカータグかどうかを判断することが含まれます。

詳細については、composedPathに関するMDNのドキュメントを参照してください。

イベントは主に、イベントディスパッチャからイベントリスナーへの変更を伝えるために存在しますが、リスナーからディスパッチャへの情報を伝えるためにも使用できます。

これを行う1つの方法は、リスナーがコンポーネントの動作をカスタマイズするために使用できるAPIをイベントに公開することです。たとえば、リスナーはカスタムイベントのdetailプロパティにプロパティを設定できます。それをディスパッチコンポーネントが動作のカスタマイズに使用します。

ディスパッチャとリスナー間の通信を行うもう1つの方法は、preventDefault()メソッドを使用することです。イベントの標準的なアクションが発生しないようにするために呼び出すことができます。リスナーがpreventDefault()を呼び出すと、イベントのdefaultPreventedプロパティがtrueになります。このフラグは、その後、リスナーが動作をカスタマイズするために使用できます。

これらの両方の技術は、次の例で使用されています。