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は、単一マシンから複数マシンへの展開を迅速に実装します。

推薦する

JSコンストラクタとインスタンス化およびプロトタイプ導入の関係

目次1. コンストラクタとインスタンス化2. コンストラクターとインスタンス化の関係は何ですか? 3...

MySQLのSQL文はインデックスを使用しません

インデックス集約を使用しない MySQL クエリご存知のとおり、インデックスを追加することはクエリ速...

dockerでデプロイされたjenkinsでgitプログラムを実行する際の問題について

1. まず、gitを関連付けるときにエラーメッセージが報告されます: エラー: ビルドするリビジョン...

MySQL テーブル構造を Excel にエクスポートする方法

要件は次のとおりですテーブル構造、フィールドコメント情報、テーブル名などをエクスポートします。これは...

MySQL の FIND_IN_SET() と IN の違いを簡単に分析します

以前、あるプロジェクトでMysql FIND_IN_SET関数を使用したことがありますが、非常に便利...

VueにExcelテーブルプラグインを導入する方法

この記事では、Excelテーブルプラグインを導入するVueの具体的なコードを参考までに共有します。具...

node.js で PC 上の WeChat アプレット パッケージを復号化するための処理アイデア

目次アプレットのソースコードはどこにありますか? PC ミニプログラムはどのように暗号化されますか?...

「いいね!」文がインデックスに登録されないのはなぜですか?

序文この記事は、最も人気のある言語で最も退屈な基礎知識を説明することを目的としていますこのトピックは...

CentOS7 で Jenkins+Maven+Git 継続的インテグレーション環境を構築する方法

この記事では、Spring boot + Maven プロジェクトのデプロイメントを例に、Code ...

MySQLの日付と時刻の間隔計算の分析例

この記事では、例を使用して、MySQL の日付と時刻の間隔計算について説明します。ご参考までに、詳細...

MySQL マスタースレーブレプリケーションの実装手順

目次mysql マスタースレーブレプリケーションMySQL マスタースレーブレプリケーション方式My...

Docker x509 の安全でないレジストリ問題を解決する

Docker をインストールした後、会社が構築したプライベート サーバー Harbor からプルしよ...

アイデアがWebプロジェクトを公開した後、Tomcatサーバーがプロジェクトとそのソリューションを見つけることができません

概要プロジェクトは正常に作成され、正常にデプロイされましたが、以下に示すように、Tomcat サーバ...

WeChatアプレットはキャンバスを使用して時計を描画します

この記事では、キャンバスを使用してWeChatアプレットに時計を描く具体的なコードを参考までに共有し...

Windows Server 2016 に Oracle をインストールする方法

1. Oracle をインストールします。インターネット上には Oracle のインストール手順が多...