ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScriptのイベント処理機構の解析

JavaScriptのイベント処理機構の解析

小云云
小云云オリジナル
2018-03-05 15:43:212475ブラウズ

イベントは JavaScript アプリケーションの心臓部であり、すべてをまとめる接着剤です。イベントは、ブラウザーで Web ページと特定の種類の操作を実行すると発生します。イベントとは、ユーザーが何かをクリックしたり、マウスを特定の要素の上に移動したり、キーボードの特定のキーを押したりすることです。イベントは、Web ページの読み込みや、ユーザーによるウィンドウのスクロールやサイズ変更など、Web ブラウザーで発生することもあります。

JavaScript を使用すると、特定のイベントの発生をリッスンし、それらのイベントに応答して特定のイベントが発生するように指定できます。

今日のイベント

長い進化の歴史の中で、私たちはインラインイベント処理メソッド(HTML要素内で直接イベントハンドラーを使用する)に別れを告げました。現在のイベントはすでに DOM の重要な部分になっています。残念ながら、IE は IE4.0 で最初に実装されたイベント モデルを引き続き維持しており、その後の IE バージョンでも大きな変更は加えられていません。これは、IE が依然として独自のイベント モデルを使用していることを意味します。バブル タイプ)、その他の主流ブラウザは、DOM レベル 3 の規制が完了するまで、DOM 標準イベント処理モデル (キャプチャ タイプとバブリング タイプ) を段階的にサポートしていませんでした。

その歴史的な理由は次のとおりです。W3C 仕様では DOM レベル 1 のイベントが定義されていませんでした。2000 年 11 月にリリースされた DOM レベル 2 までは、DOM レベル 2 ではより詳細で微妙な方法がすでに定義されていました。 Web ページ内のイベントを制御するための機能が追加され、最終的に 2004 DOM レベル 3 仕様で完全なイベントが完成しました。 IE4は1995年に登場し、独自のイベントモデル(バブル型)を実装していたため、当時はDOM標準が存在しませんでしたが、その後のDOM標準仕様の策定過程でIEのイベントモデルが吸収されました。

現在、IE ブラウザに加えて、他の主流の Firefox、Opera、Safari はすべて標準の DOM イベント処理モデルをサポートしています。 IE は依然として独自のイベント モデル、つまりバブリング タイプを使用しています。これは、開発者にとっては
DOM 標準を使用することによってのみ有効です。すべてのブラウザで効果を発揮する可能性があります。

DOMイベントフロー

DOM(Document Object Model)構造は、HTML要素がイベントを生成すると、そのイベントは要素ノードとルートノードの間で特定の順序で伝播されます。ノードはイベントを受信します。この伝播プロセスは DOM イベント フローと呼ばれます。

イベント シーケンスには、イベント キャプチャとイベント バブリングの 2 種類があります。

イベントバブリング

これは IE ブラウザーのイベント モデルの実装であり、最も理解しやすく、少なくとも私はより現実的だと思います。バブリングとは、その名前が示すように、イベントが水の中の泡のように泡立ち、頂点に達することです。 DOM ツリー構造の観点から見ると、イベントはリーフ ノードから祖先ノードに沿ってルート ノードまで渡されます。ブラウザ インターフェイス ビューの HTML 要素配置レベルからは、イベントは従属関係を持つ最も確実なターゲット要素から渡されます。最も不確実なターゲット要素。バブリング イベントの基本的な考え方は、

イベントのキャプチャ (イベント キャプチャ)

の逆です。 DOM ツリーの最上位要素から最も正確な要素までのバブリング タイプ。直感的に理解できるのはバブリング タイプであるため、開発者 (少なくとも私は...) にとっては少しわかりにくいです。イベント配信は、最も確実な要素であるイベント生成要素から開始する必要があります。

JavaScriptのイベント処理機構の解析

DOM標準イベントモデル

上記の2つの異なるイベントモデルを説明し、比較しました。 DOM 標準は、イベントのキャプチャとバブリング イベントという 2 つのイベント モデルを同時にサポートします。ただし、イベントのキャプチャが最初に発生します。どちらのイベント ストリームも、ドキュメント オブジェクトから始まりドキュメント オブジェクトで終わる、DOM 内のすべてのオブジェクトをトリガーします (標準に準拠したブラウザのほとんどは、引き続きイベントをキャプチャ/ウィンドウ オブジェクトにバブルします)。

JavaScriptのイベント処理機構の解析

図に示すように、最初はキャプチャイベント配信、次にバブリング配信です。 したがって、処理関数がキャプチャイベント監視とバブリングイベント監視の両方を登録すると、DOM イベントモデルになります。 2回呼ばれました。

DOM 標準イベント モデルの最もユニークな機能は、テキスト ノードもイベントをトリガーすることです (IE にはありません)。

JavaScriptのイベント処理機構の解析

イベント送信

DOM 標準におけるイベント フローの原則をより良く説明するために、より具体的に説明するために「イベント送信」の概要にそれを入れました。

明らかに、クリック イベント リスナーがハイパーリンクに追加されている場合、リンクがクリックされたときにイベント リスナーが実行されます。ただし、イベント リスナーが DOM ツリーの最上部にあるリンクまたはドキュメント ノードを含む p 要素に割り当てられている場合、リンクをクリックするとイベント リスナーもトリガーされます。これは、イベントがトリガーされる要素に影響を与えるだけでなく、DOM 構造に沿ったすべての要素に影響を与えるためです。これはイベント転送と呼ばれます。

W3C イベント モデルは、イベント転送の原則を明確に示しています。イベント配信は3つのステージに分けることができます。

JavaScriptのイベント処理機構の解析

図に示すように: 標準イベント転送モード

(1) イベントのキャプチャ (キャプチャ) フェーズでは、イベントは DOM ツリーに沿ってターゲット ノードの各祖先ノードに転送されます。目的のノードまで。たとえば、ユーザーがハイパーリンクをクリックすると、クリック イベントがドキュメント ノードから、リンクを含む html 要素、body 要素、および p 要素に転送されます。

このプロセス中に、ブラウザはイベントのキャプチャ イベント リスナーを検出し、イベント リスナーを実行します。

(2). ターゲット フェーズでは、ブラウザはターゲット イベントに割り当てられたイベント リスナーを見つけた後、イベント リスナーを実行します。ターゲット ノードは、イベントをトリガーした DOM ノードです。たとえば、ユーザーがハイパーリンクをクリックした場合、そのリンクがターゲット ノードになります (この場合、ターゲット ノードは実際にはハイパーリンク内のテキスト ノードです)。

(3). バブリング段階では、イベントは DOM ツリーを上に転送され、ターゲット要素の祖先ノードが 1 つずつドキュメント ノードに再度アクセスされます。あらゆる段階で。ブラウザは、キャプチャ イベント リスナーではないイベント リスナーを検出し、実行します。

すべてのイベントがバブリングステージを通過するわけではありません

すべてのイベントはキャプチャステージとターゲットステージを通過しますが、一部のイベントはバブリングステージをスキップします。たとえば、要素に入力フォーカスを取得させる focus イベントや、要素に入力フォーカスを失う原因となる Blur イベントはバブルしません。

イベント ハンドラーとイベント リスナー

イベント ハンドル

イベント ハンドル (イベント処理関数とも呼ばれます。DOM ではイベント リスニング関数と呼びます)、イベントに応答して呼び出される関数はイベント処理関数
と呼ばれます。各イベントはイベント ハンドラーに対応し、プログラムが実行されると、イベント ハンドラーに対応する関数またはステートメントが割り当てられ、イベントが発生するとブラウザーが指定された関数またはステートメントを実行することで、Web ページのコンテンツとユーザーの統合が実現されます。インタラクション。ブラウザはイベントの発生を検出すると、そのイベントに対応するイベント ハンドラーに値が割り当てられているかどうかを検索し、割り当てられている場合はそのイベント ハンドラーを実行します。

クリックイベントに応答する関数は、onclickイベント処理関数であると考えられます。以前は、イベント ハンドラーは JavaScript または HTML の 2 つの方法で割り当てられていました。

JavaScript でイベント ハンドラー関数を割り当てる場合は、まず処理対象のオブジェクトへの参照を取得し、次にその関数を対応するイベント ハンドラー関数の属性に割り当てる必要があります。簡単な例を参照してください:

1 var link=document.getElementById("mylink");2 link.onclick=function(){3   alert("I was clicked !");4 };

。私たちの観点から上記の例では、イベント ハンドラーの使用は簡単であることがわかりましたが、イベント ハンドラーの関数名は小文字である必要があり、イベント ハンドラーは要素がロードされた後にのみ要素に割り当てることができます。そうでない場合は、例外であってください。

ドキュメント読み込みテクノロジーについては、「Window.onload 読み込みのための複数のソリューション」の記事を参照してください。

イベント ハンドラーが HTML で割り当てられている場合は、HTML 属性を通じてイベント ハンドラー関数を直接設定し、適切なスクリプトを属性値として含めます。たとえば、次のとおりです。

<a>......</a>

この種の JavaScript コードと HTML スタイル属性は、CSS プロパティを要素に直接割り当てることに似ています。これにより、コードが乱雑に見え、動的な動作を実装するコードとドキュメントの静的なコンテンツを表示するコードを分離するという原則に違反します。 1998 年以降、この書き方は廃止されました。

この従来のイベント バインディング テクノロジには明らかな利点と欠点があります:

* シンプルで便利です。処理関数のコード ブロックを HTML に直接記述し、JS 内の要素の対応するイベント属性に値を割り当てるだけです。

*IE と DOM の両方の標準でサポートされているメソッド。IE と DOM の両方の標準でイベントのバブリング処理中に呼び出されます。

*処理ファンクションブロックでイベントを登録した要素を直接参照することができます。これは現在の要素を参照します。

※1つの要素に対して複数のリスナーを登録したい場合、この方法は使用できません。

イベント リスナー

すでに導入されている単純なイベント ハンドラーに加えて、ほとんどのブラウザには、より高度なイベント処理メソッド、つまりイベント リスナーが組み込まれています。この処理メソッドは、イベント ハンドラーが実行できる要素に限定されません。束縛される。

イベント ハンドラーとイベント リスナーの最大の違いは、イベント ハンドラーを使用する場合は一度に 1 つのイベント ハンドラーのみをプラグインできるのに対し、イベント リスナーの場合は一度に複数のイベント ハンドラーをプラグインできることであることはすでにわかっています。

IEでのイベントリスナー:

IE提供的却是一种自有的,完全不同的甚至存在BUG的事件监听器,因此如果要让脚本在本浏览器中正常运行的话,就必须使用IE所支持的事件监听器。另外,Safari 浏览器中的事件监听器有时也存在一点不同。

在IE中,每个元素和window对象都有两个方法:attachEvent方法和detachEvent方法。 

1 element.attachEvent("onevent",eventListener);

此方法的意思是在IE中要想给一个元素的事件附加事件处理函数,必须调用attachEvent方法才能创建一个事件监听器。attachEvent方法允许外界注册该元素多个事件监听器。

attachEvent接受两个参数。第一个参数是事件类型名,第二个参数eventListener是回调处理函数。这里得说明一下,有个经常会出错的地方,IE下利用attachEvent注册的处理函数调用时this指向不再是先前注册事件的元素,这时的this为window对象。还有一点是此方法的事件类型名称必须加上一个”on”的前缀(如onclick)。 

1 element.attachEvent("onevent",eventListener);

要想移除先前元素注册的事件监听器,可以使用detachEvent方法进行删除,参数相同。

DOM标准下的事件监听器:

在支持W3C标准事件监听器的浏览器中,对每个支持事件的对象都可以使用addEventListener方法。该方法既支持注册冒泡型事件处理,又支持捕获型事件处理。所以与IE浏览器中注册元素事件监听器方式有所不同的。

1 //标准语法 2 element.addEventListener(&#39;event&#39;, eventListener, useCapture);3 //默认4 element.addEventListener(&#39;event&#39;, eventListener, false);

addEventListener方法接受三个参数。第一个参数是事件类型名,值得注意的是,这里事件类型名称与IE的不同,事件类型名是没’on’开头的;第二个参数eventListener是回调处理函数(即监听器函数);第三个参数注明该处理回调函数是在事件传递过程中的捕获阶段被调用还是冒泡阶段被调用 ,通常此参数通常会设置为false(为false时是冒泡),那么,如果将其值设置为true,那就创建一个捕捉事件监听器。

移除已注册的事件监听器调用element的removeEventListener方法即可,参数相同。

1 //标准语法 2 element.removeEventListener(&#39;event&#39;, eventListener, useCapture);3 //默认4 element.removeEventListener(&#39;event&#39;, eventListener, false);

通过addEventListener方法添加的事件处理函数,必须使用removeEventListener方法才能删除,而且要求参数与添加事件处理函数时addEventListener方法的参数完全一致(包括useCapture参数),否则将不能成功删除事件处理函数。

跨浏览器的注册与移除元素事件监听器方案

我们现在已经知道,对于支持addEventListener方法的浏览器,只要需要事件监听器脚本就都需要调用addEventListener方法;而对于不支持该方法的IE浏览器,使用事件监听器时则需要调用attachEvent方法。要确保浏览器使用正确的方法其实并不困难,只需要通过一个if-else语句来检测当前浏览器中是否存在addEventListener方法或attachEvent方法即可。

这样的方式就可以实现一个跨浏览器的注册与移除元素事件监听器方案:

 1 var EventUtil = {
 2   //注册
 3   addHandler: function(element, type, handler){
 4     if (element.addEventListener){
 5       element.addEventListener(type, handler, false);
 6     } else if (element.attachEvent){
 7       element.attachEvent("on" + type, handler);
 8     } else {
 9       element["on" + type] = handler;
10     }
11   },
12   //移除注册
13   removeHandler: function(element, type, handler){
14     if (element.removeEventListener){
15             element.removeEventListener(type, handler,                false);
16     } else if (element.detachEvent){
17             element.detachEvent("on" + type, handler);
18     } else {
19             element["on" + type] = null;
20     }
21   }             
22  }; 

JavaScriptのイベント処理機構の解析

イベント オブジェクト リファレンス

イベントをより適切に処理するために、発生したイベントの特定のプロパティに基づいてさまざまなアクションを実行できます。

イベント モデルと同様に、IE は他のブラウザとは異なる方法でオブジェクトを処理します。IE は、event と呼ばれるグローバル イベント オブジェクトを使用してオブジェクトを処理します (グローバル変数 window.event にあります)。他のすべてのブラウザは W3C 推奨メソッドを使用します。イベント オブジェクトを含む独立したパラメーターの受け渡しを使用します。

このような関数を複数のブラウザーに実装する場合、最も一般的な問題は、イベント自体への参照を取得し、イベントのターゲット要素への参照を取得することです。

次のコードは、この問題を解決します:

1 var EventUtil ={
2 getEvent: function(event){
3 return event events : window.event;
4 },
5 getTarget: function (event) ){
6 returnevent.target ||event.srcElement;
7 }
8};

イベントのバブリングを停止し、イベントのデフォルト動作をブロックします

「イベントのバブリングを停止する」と「ブラウザのデフォルト動作をブロックする」、これら 2 つの概念は次のとおりです。非常に重要であり、複雑なアプリケーション処理に非常に役立ちます。

1. イベントバブリングの停止

イベントバブリングの停止とは、バブリングイベントのさらなる配信を停止することを意味します(イベント配信をキャンセルします。IE および DOM 標準に共通のバブリングイベントを停止するだけでなく、DOM 標準ブラウザキャプチャイベントのサポートも停止できます)。 topPropagation() メソッドを使用します)。たとえば、上図のバブリングイベント配信では、本文処理がイベント配信を停止すると、上部ドキュメントのイベントリスナーは通知を受信しなくなり、処理されなくなります。

2. イベントをブロックするデフォルトの動作

イベントを停止するデフォルトの動作は、通常、イベントが配信され処理された後に、ブラウザーがイベントに関連付けられたデフォルトのアクション (そのようなアクションが存在する場合) を実行することを意味します。たとえば、フォームの入力タイプ属性が「submit」の場合、クリック後にイベントが伝播された後、ブラウザはフォームを自動的に送信します。別の例として、input 要素の keydown イベントが発生して処理された後、ブラウザーはデフォルトでユーザーが入力した文字を input 要素の値に自動的に追加します。

イベントバブリングを停止する方法:

IEでは、イベントオブジェクトのcancelBubbleをtrueに設定するだけです。

1 function someHandle() {
2 window.event.cancelBubble = true;
3}

DOM 標準では、イベント オブジェクトの stopPropagation() メソッドを呼び出します。

1 function someHandle(event) {
2 events.stopPropagation();
3}

したがって、クロスブラウザーの停止イベント配信メソッドは次のとおりです。 window.event;

3 if(event.stopPropagation){

4 events.stopPropagation();
5 }else {
6 events.cancelBubble = true;
7 }
8 }

イベントをブロックするデフォルトの動作 処理メソッド

イベント モデルとイベント オブジェクトの違いと同様に、イベントのデフォルト動作を防ぐ方法も IE と他のすべてのブラウザーで異なります。

IEでは、イベントオブジェクトのreturnValueをfalseに設定するだけです。

1 function someHandle() {

2 window.event.returnValue = false;

3}


DOM 標準は、イベント オブジェクトのPreventDefault() メソッドを呼び出すことで実行できます。

1 function someHandle(event) {

2 events.preventDefault();

3}


このため、クロスブラウザキャンセルイベントが渡された後のデフォルトの処理メソッドは次のようになります。

1 function someHandle(event) {

2 イベント = イベント ||

3 if(event.preventDefault){

4 events.preventDefault();
5 }else{
6 events.returnValue = false;
7 }
8 }

Completeイベント処理互換関数

1 var EventUtil = {
2 addHandler: function(element, type, handler){
3 if (element.addEventListener){
4 element.addEventListener(type, handler, false);
5 } else if (要素.attachEvent ){
6 element.attachEvent("on" + type, handler);
7 } else {
8 element["on" + type] = handler;
9 }
10 },
11 removeHandler:関数(要素, type, handler){
12 if (element.removeEventListener){
13 element.removeEventListener(type, handler, false);
14 } else if (element.detachEvent){
15 element.detachEvent("on" + type, handler);
16 } else {
17 element["on" + type] = null;
18 }
19 },
20 getEvent: function(event){
21 return event ? イベント: window.event;
22 },
23 getTarget: function(event){
24 return event.target || events.srcElement;
25 },
26 preventDefault: function(event){
27 if (event.preventDefault){
28 event.preventDefault();
29 } else {
30 event.returnValue = false;
31 }
32 },
33 stopPropagation: function(event){
34 if (event.stopPropagation){
35 event.stopPropagation();
36 } else {
37 event.cancelBubble = true ;
38 }
39 };

捕捉型イベント モデルと冒険型イベント モデルのアプリケーション

標準イベント モデルは、私たちが 2 つの方式を提供するため、おそらく多くの友人がこの 2 つの異なるモデルに優れた点を備えており、どちらか 1 つのモデルだけを採用するわけではありません。
ここでは IE ブラウザー (IE は 1 つのタイプのみであり、法的に選択されません) を以下に示します。

1. キャプチャ型アプリケーションアプリケーション

キャプチャ型イベントは、最も不正確な祖先要素から最も正確なイベント ソース要素まで、オペレーティング システム内の全体的なクイック ボタンと同様の方法で送信されます。 、システム全局の快捷键监听が注目を集めた場合、そのイベントは操作システム層によって最初に捕捉され、全局の快捷监听がアプリケーションプログラムより先に通知を取得し、つまり全局が先に制御を取得し、イベントが阻止されます。捕捉型イベントモデルは、ここでの全ローカルとは相対的な特定の全ローカルであり、そのトップレイヤポイントとそのポイントに対してすべての子レイヤポイントが形成するセットとして使用されるのに適している。局所的なポイントイベントを考え、ドキュメントポイントとドキュメントの下のすべての子ポイントに対して、特定の条件下ですべての子ポイントポイントが無効果であることを要求し、この状況を冒涜するモデルが解決されずに捕らえられます。型は非常に適しており、最顶层结点で捕捉型イベント监听器を追加できます、伪码如下:

1 function globalClickListener(event) {


2 if(canEventPass == false) {

3 //イベント取り消し向子结点传递和冒泡传递

4 event.stopPropagation();
5 //取消浏览器イベント後の默认実行
6 event.preventDefault();
7 }
8 }

JavaScriptのイベント処理機構の解析这样一

2. canEventPass 条件が設定されている場合、ドキュメント内のすべての子ポイントクリックイベントは処理されません。 冒険泡型の応用场合

IE はこのモデルのみをサポートしているため、通常はバブリング イベント モデルを使用していると言えます。このモデルを適切に使用すると、スクリプトのパフォーマンスが向上します。 onmousemove、onmouseover、onmouseout など、要素の頻繁にトリガーされる一部のイベントでは、処理後にイベントをさらに渡す必要がないことが明らかな場合は、大胆にキャンセルできます。また、子ノードのイベントリスナーの処理が親層のリスナーの処理に悪影響を与える場合には、その影響を排除するために子ノードのリスナーにおいてもイベントの上向き送信を禁止する必要があります。

包括的なケース分析

最後に、分析のために次の HTML コードと組み合わせます:

1

2


3


4


5


6 これは、赤い領域をクリックします。一番内側のp. 上記の説明によると、DOM標準でもIEでも、 HTMLで直接書いたlisten処理関数はイベントがバブルされて渡されると呼び出され、最内層から順に渡されていきます
currentがevent_source
currentがp2
currentがp1
currentがp0
現在は body です

次のフラグメントを追加します:

1 var p2 = document.getElementById('p2');
2 EventUtil .addHandler(p2, 'click', function(event){
3 events = EventUtil.getEvent( event);
4 EventUtil.stopPropagation(event);

5}, false);

currentはevent_sourcecurrentはp2


上記の説明によれば、バブリングプロセス中に赤い領域をクリックすると、イベントが渡されましたp2 に送信して停止したため、p2 の上位要素は通知を受け取らなかったため、通知が次々に表示されます:

DOM 標準をサポートするブラウザの場合 コンテナに次のコードを追加します:

1 document.body.addEventListener ('click', function(event){

2event.stopPropagation();

3}, true);

上記のコードのlisten関数は 渡すときにキャプチャタイプが呼び出されるので、赤い部分をクリックした後、イベント ソースは、event_source という ID を持つ要素ですが、キャプチャ タイプが渡されます。トップ レベルから開始して、body ノードのリッスン関数が最初に呼び出され、イベントがキャンセルされてさらに転送されるため、current のみが渡されます。体が現れます。

関連する推奨事項:


node.js のイベント処理メカニズムの詳細な説明

JavaScript ブラウザー互換性イベント処理メカニズム


クロスブラウザー イベント処理メカニズムを作成するための JavaScript [Blue-Dream 制作]_javascriptスキル

以上がJavaScriptのイベント処理機構の解析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。