JSブラウザイベントモデルの詳細な説明

JSブラウザイベントモデルの詳細な説明

イベントとは

イベント駆動型という言葉を聞いたことがあると思いますが、イベント駆動型とは一体何でしょうか?ブラウザがイベント駆動型なのはなぜですか?

簡単に言えば、イベント駆動型とは、すべてがイベントに抽象化されることを意味します。

  • クリックはイベントです
  • キーボードの押下はイベントです
  • ネットワークリクエストが成功するとイベントが発生します
  • ページの読み込みはイベントです
  • ページエラーはイベントです

ブラウザはイベントを利用してアプリを実行します。イベント駆動がない場合、アプリは最初から最後まで直接実行され、その後終了します。イベント駆動はブラウザの基礎です。

簡単な例

実は、現実の信号機は一種のイベントです。信号機は、赤信号の状態か、青信号の状態か、黄信号の状態かを伝えます。 このイベントに基づいていくつかの操作を完了する必要があります。たとえば、赤信号と黄色信号を待つ必要があり、信号が緑のときに道路を渡ることができます。

最も単純なブラウザ イベントを見てみましょう。

HTMLコード:

<button>色を変更する</button>

jsコード:

var btn = document.querySelector('ボタン');

btn.onclick = 関数() {
  console.log('ボタンがクリックされました')
}

コードは非常にシンプルです。ボタンにイベントを登録します。このイベントのハンドラーは、定義した匿名関数です。ユーザーがイベントに登録されたボタンをクリックすると、定義した匿名関数が実行されます。

イベントをバインドする方法

イベントをバインドする方法には、インライン バインディング、直接割り当て、addEventListener の使用の 3 つがあります。

このメソッドをインライン化することは強く推奨されません

HTMLコード:

<button onclick="handleClick()">押してください</button>

次に、スクリプト タグに次のように記述します。

関数handleClick() {
  console.log('ボタンがクリックされました')
}

直接割り当て

上で示した例のように:

var btn = document.querySelector('ボタン');

btn.onclick = 関数() {
  console.log('ボタンがクリックされました')
}

このアプローチには2つの欠点がある

同じタイプのハンドラーを複数追加することはできません。

btn.onclick = 関数A;
btn.onclick = 関数B;

この方法では functionB のみが有効になり、addEventListener によって解決できます。

どの段階で実行が行われるかを制御することはできません。これについては、後でイベントのキャプチャ/バブリング時に説明します。これもaddEventListenerで解決できます。

そこで、現在推奨されている書き方でもある addEventListener が誕生しました。

イベントリスナーの追加

旧バージョンの addEventListener の 3 番目のパラメータは bool ですが、新バージョンの 3 番目のパラメータは object です。これは、その後の拡張に便利で、より多くの機能を持ちます。これに注目してみましょう。

addEventListener は、イベントを Element、Document、Window、さらには XMLHttpRequest にバインドできます。指定されたイベントが発生すると、バインドされたコールバック関数が特定のメカニズムによって実行されます。これについては後で説明します。

文法:

target.addEventListener(type, listener[, options]);
target.addEventListener(type, listener[, useCapture]);
target.addEventListener(type, listener[, useCapture, wantsUntrusted ]); // Gecko/Mozilla のみ

type はバインドするイベント タイプです。一般的なものはクリック、スクロール、タッチ、マウスオーバーなどです。古いバージョンの 3 番目のパラメーターは bool で、キャプチャ フェーズであるかどうかを示します。デフォルトは false です。つまり、デフォルトはバブリング フェーズです。新しいバージョンは、キャプチャ (上記と同じ機能)、パッシブ、および once を含むオブジェクトです。 Once は、1 回だけ実行するかどうかを決定するために使用されます。passive が true に指定されている場合、preventDefault() は実行されません。これは、スムーズなスクロール効果を実現するために重要です。詳細については、「パッシブ リスナーによるスクロール パフォーマンスの向上」を参照してください。

フレームワーク内のイベント

実際、今ではフレームワークを使ってコードを書くことが多いので、上記のような状況は現実的には非常に稀です。React の合成イベントなど、フレームワークによってカプセル化されたイベントをよく見かけます。興味があれば、これらの記事を読んでみてください。

  • React 合成イベント
  • Vue と React のそれぞれの利点は何ですか?両者の根本的な違いは何でしょうか?

ネイティブ イベントに遭遇することはほとんどありませんが、フレームワークのイベント システムは少なくともこの点では一貫しているため、イベント オブジェクト、イベント メカニズム、イベント エージェントなどを理解する必要があります。これについては次に説明します。

イベントオブジェクト

すべてのイベント処理関数は、ブラウザによって実行されるときにイベント オブジェクトを伴います。例:

関数handleClick(e) {
  コンソールログ(e);
}  

btn.addEventListener('click', handleClick);

この e はイベント オブジェクトです。 このオブジェクトには非常に便利なプロパティとメソッドがいくつかあります。ここでは、よく使用されるプロパティとメソッドをいくつか紹介します。

財産

  • ターゲット
  • x、y、その他の位置情報
  • タイムスタンプ
  • イベントフェーズ

方法

  • preventDefault は、デフォルトで a タグがジャンプしたり、デフォルトでフォームが検証され、アクションで指定されたアドレスにリクエストが送信されるなど、ブラウザのデフォルトの動作を防止するために使用されます。
  • stopPropagation は、イベントのさらなるバブリングを停止するために使用されます。これについては、後でイベントの伝播について説明するときに説明します。

イベントの伝播

前述のように、イベントはデフォルトでバブリング フェーズにバインドされます。useCapture を明示的に true に設定すると、イベントはキャプチャ フェーズにバインドされます。

イベント キャプチャは非常に興味深いので、イベントに関する質問をしたり、イベント伝播メカニズムを追加したり、候補者に回答を求めたりすることがよくあります。これは、人のレベルを本当に反映することができます。イベントの伝播メカニズムを理解することは、特定の問題に非常に役立ちます。

要素にバインドされたイベントがトリガーされると、実際には 3 つの段階を経ます。

フェーズ 1 - キャプチャフェーズ

最も外側のレイヤー、つまり HTML タグから始めて、現在の要素に対応するキャプチャ フェーズ イベントがバインドされているかどうかを確認します。バインドされている場合はそれを実行し、バインドされていない場合は内部に伝播し続けます。このプロセスは、イベントをトリガーする要素に到達するまで再帰的に実行されます。

疑似コード:

関数キャプチャ(e, 現在の要素) {
    (currentElement.listners[e.type] !== void 0)の場合{
        currentElement.listners[e.type].forEach(fn => fn(e))
    }


    // 渡す
    (現在の要素 !== e.target) の場合 {
        // getActiveChild は、現在のイベント伝播リンク上の子ノードの取得に使用されます。capture(e, getActiveChild(currentElement, e))
    } それ以外 {
        バブル(e, 現在の要素)
    }
}

// このイベントオブジェクトはエンジンによって作成されます capture(new Event(), document.querySelector('html'))

第2段階 - 目標段階

これについては上で述べたので、ここでは省略します。

第3段階 - 泡立ち段階

このイベントをトリガーする要素から始めて、現在の要素にバインドされた対応するバブリング ステージ イベントがあるかどうかを確認します。ある場合はそれを実行し、ない場合は伝播を続けます。このプロセスは、HTML に到達するまで再帰的に実行されます。

疑似コード:

関数バブル(e, 現在の要素) {
    (currentElement.listners[e.type] !== void 0)の場合{
        currentElement.listners[e.type].forEach(fn => fn(e))
    }
    // 戻る
    現在の要素が document.querySelector('html') の場合 {
        バブル(e, 現在の要素.parent)
    }
}

上記のプロセスは図で表されます。

イベントのバブルを継続したくない場合は、前述の stopPropagation を使用できます。

疑似コード:

関数バブル(e, 現在の要素) {
    停止 = false にします。
    関数cb() {
        停止 = true;
    }
    (currentElement.listners[e.type] !== void 0)の場合{
        currentElement.listners[e.type].forEach(fn => {
            関数({
                ...e、
                伝播停止: cb
            });
            (停止した場合)戻ります。
        })
    }
    // 戻る
    現在の要素が document.querySelector('html') の場合 {
        バブル(e, 現在の要素.parent)
    }
}

イベント委任

上で説明したイベント バブリング メカニズムを使用すると、いくつかの興味深いことを行うことができます。 例えば:

次のようなリストがあり、対応するリスト項目をクリックしたときにどの要素がクリックされたかを出力したいと考えています。

HTMLコード:

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
</ul>

JSコード:

document.querySelector('ul').addEventListener('click', e => console.log(e.target.innerHTML))

オンライン アドレス、前述のように、addEventListener はデフォルトでバブリング ステージにバインドされるため、イベントはターゲット ステージから開始され、イベントをバインドした ul の外側のレイヤーにバブリングします。ul では、イベント オブジェクトの target 属性を通じて、どの要素がイベントをトリガーしたかを取得できます。

「イベントはターゲットフェーズから開始されます」とは、イベントにキャプチャフェーズがないという意味ではなく、キャプチャフェーズをバインドしなかったという意味なので、説明では省略しました。

イベント処理関数を外側の ul にバインドするだけですが、li がクリックされると、対応する li コンテンツ (1、2、3、または 4) が実際に印刷されることがわかります。 各 li にイベント処理関数をバインドする必要がないため、コードの量だけでなくパフォーマンスも向上します。

私たちはこの興味深いものに「イベント プロキシ」という素敵な名前を付けました。この手法は実際のビジネスでもよく使われますし、面接でも高頻度にテストされるポイントです。

要約する

イベントはブラウザ固有のものではなく、JS 言語とは関係がないため、JS セクションに分類しませんでした。多くの場所にイベント システムがありますが、イベント モデルは一貫していません。

今日お話しするのは、ブラウザのイベント モデルです。ブラウザはイベント駆動型であり、ユーザー操作、ネットワーク リクエスト、ページの読み込み、エラーなど、多くのことをイベントに抽象化します。イベントは、ブラウザの正常な動作の基礎であると言えます。

私たちが使用するフレームワークはすべて、さまざまな程度にイベントをカプセル化して処理します。ネイティブ イベントと原則を理解するだけでなく、フレームワーク自体がイベントを処理する方法を理解することも必要な場合があります。

イベントが発生すると、ブラウザはイベント オブジェクトを初期化し、特定のロジックに従ってイベント オブジェクトを伝播します。このロジックがイベント伝播メカニズムです。 イベントの伝播は実際には、時系列順にキャプチャ ステージ、ターゲット ステージ、バブリング ステージの 3 つのステージに分かれていることを説明しました。開発者は、望ましい効果を得るためにさまざまな段階を監視することを選択できます。

イベント オブジェクトには、クリックの座標情報の読み取り、バブリングの防止など、イベント処理機能で読み取りや操作を行うことができるプロパティやメソッドが多数あります。

最後に、バブリング メカニズムを使用してイベント委任を実装する方法を例を使って説明します。

以上がJSブラウザイベントモデルの詳しい説明です。JSブラウザイベントモデルについてさらに詳しく知りたい方は、123WORDPRESS.COMの他の関連記事もぜひご覧ください!

以下もご興味があるかもしれません:
  • ネイティブ JS を使用してタッチスライド監視イベントを実装する方法
  • JavaScript WebAPI、DOM、イベント、操作要素例の詳しい説明
  • JavaScript におけるイベント バブリング メカニズムの詳細な分析
  • jsのイベントループ機構の解析
  • JS と Nodejs におけるイベント駆動型開発についての簡単な説明
  • Vue.js フロントエンドフレームワークにおけるイベント処理の概要
  • 一般的なイベントを処理するための JavaScript の使用に関する詳細な説明
  • JavaScript イベント ループのケース スタディ

<<:  MySQL共通ストレージエンジンの機能と使用方法の詳細な説明

>>:  Redission-tomcatは、単一マシンから複数マシンへの展開を迅速に実装します。

推薦する

Linux リダイレクトの使用方法の詳細な説明

誰でも時々データをコピーして貼り付ける必要があると思います。コピーして貼り付けるためにファイルを開く...

MySQL の WriteSet 並列レプリケーションの簡単な分析

【歴史的背景】私は 3 年間 MySQL-DBA として働いてきましたが、MySQL が「基本的に利...

ユニアプリとミニプログラム(画像とテキスト)を下請けする方法を教えます

目次1. ミニプログラム下請け2. Uniapp 下請けアプレット下請けの手順: 1. manife...

MySQLの重複排除方法

MySQLの重複排除方法【初級】繰り返しのセリフが少ないdistinctive を使用してそれらを見...

Mac OS に MySQL 5.7.20 をインストールするための詳細なグラフィックとテキストの説明

Mac OS X で TAR.GZ から MySQL 5.7 をインストールする MySQL 5.6...

コネクタコンポーネントから Tomcat のスレッドモデルを見る - BIO モード (推奨)

Tomcat の上位バージョンでは、デフォルト モードは NIO モードを使用することになります。...

時点別のMySQLデータベース復旧実績

はじめに: 時間ポイントによる MySQL データベースの復旧どの企業にとっても、データは最も価値の...

MySQL バージョン 5.7.24 のデータベース インストール プロセスの詳細なグラフィック説明

MySQL は最も人気のあるリレーショナル データベース管理システムです。WEB アプリケーションに...

HTMLでカスタムタグを使用する方法

カスタム タグは XML ファイルと HTML ファイルで自由に使用できますが、いくつか注意すべき点...

MySQLのデフォルトのソートルールに基づく落とし穴

MySQL のデフォルトの varchar 型は大文字と小文字を区別しません (insensitiv...

Windows 10 でカスタムドメイン名をバインドするように Hexo と GitHub を構成する方法

Hexo は Windows 10 でカスタムドメイン名を GitHub にバインドしますまずドメイ...

Linux での vi (vim) の新しい使い方のまとめ

私は数年間 vi エディタを使ってきましたが、実用的な用途で使ったことはありませんでした。今日 Py...

スパンの最小高さを定義するソリューションは効果がありません

span タグは HTML ウェブページを作成するときによく使用されますが、このタグの使い方がよくわ...

CentOS 7 は Hadoop 2.10 の高可用性 (HA) をビルドします

この記事では、CentOS 7 で高可用性 Hadoop 2.10 クラスターを構築する方法を紹介し...

Ubuntu 20.04 IPアドレスを変更する方法の例

例:本日、前回のオフィスコラボレーションプラットフォーム実験の続きをしていたところ、仮想マシンは以前...