JS と HTML 間の対話はイベントを通じて実現されます。イベントは、ドキュメントまたはブラウザ ウィンドウ内で発生する対話の特定の瞬間です。リスナー (またはハンドラー) を使用してイベントをスケジュールし、イベントの発生時に適切なコードが実行されるようにすることができます。従来のソフトウェア エンジニアリングではオブザーバー パターンとして知られており、これはページの動作とページの外観の間の疎結合をサポートします。この記事ではJSイベントに関する基礎知識を紹介します。
1. イベントフローイベントフローは、ページからイベントを受け取る順序を記述します。
イベントバブリング イベントは、最初に最も具体的な要素 (ドキュメント内で最も深いネストレベルを持つノード) によって受信され、その後、より具体性の低いノード (ドキュメント) に上方に伝播します。以下の HTML ページを例に挙げると、ページ上のボタンをクリックすると、37a9605a910bf1fbe848fe3f47ab78d9、1d6e7d87652dd104f173dbf7284e2799、< の順にイベントが伝播されます。つまり、イベントのバブリングとは、イベントをトリガーした基礎となる要素からドキュメント オブジェクトまで、イベントが DOM ツリーに沿って上向きに伝播することを意味します。
<html>
<head>
<title>Test</title>
</head>
<body>
<button id="myBtn">A Btn</button>
</body>
</html>
イベント キャプチャ イベント バブリングの考え方とは反対に、イベント キャプチャの考え方は、あまり具体的でないノードがより早くイベントを受信し、最も具体的なノードが最後にイベントを受信する必要があるというものです。上記の例では、ページ上のボタンをクリックした後、ドキュメント、、、 の順に「クリック」イベントが伝播されます。つまり、イベントのキャプチャとは、イベントがドキュメント オブジェクトからイベントの実際のターゲット要素まで DOM ツリーに沿って下方向に伝播することを意味します。
DOMイベントの流れ「DOM2レベルイベント」で指定されるイベントには、イベントキャプチャステージ、ターゲットステージ、イベントバブリングステージの3つのステージが含まれます。最初に行われるのはイベントのキャプチャであり、イベントを傍受する機会が提供されます。その後、実際のターゲットがイベントを受信します。最後のフェーズはバブリングフェーズで、イベントに応答できます。
前のボタンのクリックを例にとると、DOM イベント フローでは、キャプチャ フェーズ中に、「クリック」イベントがドキュメントから開始され、body 要素に渡されます (実際のターゲット ボタンはイベントを受信しないことに注意してください)キャプチャフェーズ中)。ターゲットフェーズでは、ボタン要素が「クリック」イベントを受け取ります。最後に、バブリングフェーズでは、イベントがドキュメントに伝播されます。
2. イベントハンドラー イベントとは、ユーザーまたはブラウザ自体によって実行される特定のアクションであり、イベントに応答する関数はイベント ハンドラーまたはイベント リスナーと呼ばれます。
HTML イベント ハンドラー ここでの HTML イベント ハンドラーは、HTML 要素の属性を通じて直接定義されたイベント ハンドラーを指します。以下のコード例を参照してください。この場合、イベント ハンドラーは要素の属性値をカプセル化する関数を作成します。この値はイベントのターゲット要素と等しくなります。この方法でイベント ハンドラーを指定することにはいくつかの欠点があるため、お勧めできません。
<button onclick="alert('HaHa~')">Btn-1</button>
<button onclick="alert('event.type')">Btn-2</button>
<button onclick="handler()">Btn-3</button>
<script type="text/javascript">
function handler() {
alert("Haha~");
}
</script>
DOM レベル 0 イベント ハンドラー JS を通じてイベント ハンドラーを指定する従来の方法は、イベント ハンドラー属性に関数を割り当てることです。以下のコード例を参照してください。このように指定されたイベント ハンドラーは、現在の要素を参照する要素のスコープ内で実行されます。この方法で追加されたイベント ハンドラーは、イベント フローのバブリング フェーズ中に処理されます。イベントを削除したい場合は、onclick の値を空に設定するだけです。
var btn = document.getElementById("myBtn");
btn.onclick = function() {
console.log("this.id"); // "myBtn"
};
// 删除事件处理程序
btn.onclick = null;
DOM2 レベルのイベント ハンドラー 「DOM2 レベルのイベント」では、イベント ハンドラーを指定および削除するための 2 つのメソッド、addEventListener() と RemoveEventListener() が定義されています。これら 2 つのメソッドはすべての DOM ノードに含まれています。どちらのメソッドも、処理対象のイベント、処理関数、およびブール値の 3 つのパラメーターを受け取ります。最後のブール値は、true の場合はイベント ハンドラーがキャプチャ フェーズ中に呼び出されることを意味し、false の場合はイベント ハンドラーがバブリング フェーズ中に呼び出されることを意味します。 DOM0 レベルのメソッドと同様に、ここで追加されたイベント ハンドラーも、それがアタッチされている要素のスコープ内で実行されます。 DOM2 レベルのメソッドを使用してイベント ハンドラーを追加する利点は、複数のイベント ハンドラーを追加できることです。これらのイベント ハンドラーは、追加された順序で起動されます。以下はコード例です: addEventListener() を通じて追加された
var btn = document.getElementById("myBtn");
// 添加,触发点击事件时先输出"myBtn"再输出"HaHa~"
btn.addEventListener("click", function() {
console.log(this.id);
}, false);
btn.addEventListener("click", function() {
console.log("HaHa~");
}, false);
イベントは、removeEventListener() を通じてのみ削除できます。削除時に渡されるパラメータは、追加時に使用されるパラメータと一致している必要があります。また、addEventListener()で追加した匿名関数は削除できないことも意味します。追加時に渡した匿名関数をremoveEventListener()に渡すことができないため、削除時に同じ関数を記述しても、この関数は単なるNew匿名関数になります。以下のコード例を参照してください:
var btn = document.getElementById("myBtn");
// 无法删除匿名函数
btn.addEventListener("click", function() {
console.log(this.id);
}, false);
btn.removeEventListener("click", function() {
console.log(this.id);
}, false);
// 正确的添加和删除方式
function handler() {
console.log(this.id);
}
btn.addEventListener("click", handler, false);
btn.removeEventListener("click", handler, false);
ほとんどの場合、さまざまなブラウザーとの互換性を最大限に高めるために、イベント ハンドラーはイベント フローのバブリング ステージに追加されます。イベントがターゲットに到達する前にイベントをインターセプトする必要がある場合にのみ、イベント ハンドラーをキャプチャ フェーズに追加することをお勧めします。 JS 高度なプログラミングで提供されるアドバイスは、特に必要でない場合は、イベント キャプチャ フェーズでイベント ハンドラーを登録することは推奨されないというものです。
IEイベントハンドラーIE实现了与DOM中类似的两个方法: attachEvent()和deleteEvent()。这两个方法接收两个参数,事件处理程序名称和事件处理程序。注意,第一个参数是事件处理程序名称而不是事件名称,也就是说在注册点击事件的处理程序时应该传入”onclick”而不是”click”,这里跟DOM的方法有些差别。另外,这两个方法注册的事件处理程序是在全局作用域中运行而不是元素作用域,this的值指向window。还有一点需要特别小心,通过attachEvent()方法也可以添加多个事件处理程序,但是它们的执行顺序却不是按照它们被添加的顺序,而是完全相反,跟DOM方法截然不同。突然觉得IE真的特别反人类~~~下面是代码示例:
var btn = document.getElementById("myBtn");
function handler1() { // ... }
function handler2() { // ... }
// 添加,触发点击事件时先执行handler2再执行handler1
btn.attachEvent("onclick", handler1);
btn.attachEvent("onclick", handler2);
// 删除
btn.deleteEvent("onclick", handler1);
btn.deleteEvent("onclick", handler2);
三、事件对象在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息,包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。
DOM中的事件对象兼容DOM的浏览器会将一个event对象传入事件处理程序中,无论指定事件处理程序时用的是DOM0还是DOM2的方法,都会传入event对象。event对象只有在事件处理程序执行期间才会存在,一旦事件处理程序执行完毕,event对象就会被销毁。下面是代码示例:
var btn = document.getElementById("myBtn");
btn.onclick = function(event) {
console.log(event.type); // "click"
}
btn.addEventListener("click", function(event) {
console.log(event.type);
}, false);
event对象包含与创建它的特定事件有关的属性和方法,触发的事件类型不一样,可用的属性方法也有所不同。但是所有的事件都会有下列的属性或方法:
bubbles: 布尔值,表示事件是否冒泡
cancelable: 布尔值,表示是否可以取消事件的默认行为
currentTarget: 元素,事件处理程序当前正在处理事件的那个元素
defaultPrevented: 布尔值,表示是否调用过preventDefault()方法
detail: 整数,与事件相关的细节信息
eventPhase: 整数,调用事件处理程序的阶段,1表示捕获阶段,2表示目标阶段,3表示冒泡阶段
preventDefault(): 函数,取消事件的默认行为,cancelable为true时可以调用该方法
stopImmediatePropagation(): 函数,取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用
stopPropagation(): 函数,取消事件的进一步捕获或冒泡,bubbles为true时可以调用这个方法
target: 元素,事件的目标
trusted: 布尔值,为true时表示事件是浏览器生成的,否则表示事件是通过JS创建的
type: 字符串,被触发的事件类型
view: 与事件关联的抽象视图,等同于发生事件的window对象
下面代码示例展示了上述部分属性的用法,也可以帮助我们进一步理解事件流。假设页面中有一个按钮”myBtn”。当点击按钮时,this和currentTarget都等于body元素,因为事件处理程序是注册在body元素上。target的值却等于按钮元素,因为它是click事件的真正目标。由于按钮上没有注册事件处理程序,结果”click”事件冒泡到了document.body那里才得到处理。
document.body.onclick = function(event) {
console.log(event.currentTarget === document.body); // true
console.log(this === document.body); // true
console.log(event.target === document.getElementById("myBtn")); // true
};
再看一个例子,下面代码中,stopPropagation()方法取消了事件的进一步捕获或冒泡。当我点击按钮时,本来应该会因为事件冒泡机制触发按钮和body元素上的点击事件处理程序,输出”From Bth …”和”From Body …”。现在点击事件在按钮元素上触发之后就被阻止继续在DOM层次中的传播,因此body上的事件处理程序不会被触发。
var btn = document.getElementById("myBtn");
btn.onclick = function(event) {
console.log("From Bth ...");
event.stopPropagation(); // 停止事件传播
};
document.body.onclick = function() {
console.log("From Body ...");
};
IE中的事件对象在IE中,使用DOM0的方法添加事件处理程序时,event对象作为window对象的一个属性存在。如果是通过attachEvent()方法添加,则event对象是作为参数传入事件处理函数。下面是代码示例:
var btn = document.getElementById("myBtn");
btn.onclick = function() {
var event = window.event;
console.log(event.type); // "click"
};
btn.attachEvent("onclick", function(event) {
console.log(event.type); // "click"
});
IE的event对象同样也包含与创建它的事件相关的属性和方法,这些属性和方法也会因为事件类型的不同而有所差异。但所有事件对象都会包含下列属性:
cancelBubble: 布尔值,可读可写,默认为false。将其设置为true时取消事件冒泡
returnValue: 布尔值,可读可写,默认为true。将其设置为false时取消事件的默认行为
srcElment: 元素,事件的目标元素,与DOM中的target属性相同
type: 字符串,事件类型在IE中,事件处理程序的作用域是根据指定它的方式来确定,this的值不一定是指向事件的目标元素。因此,使用srcElement属性更具保险。请看下面代码实例,第一种方式中this的值为目标元素,而第二种方式,前面讲过这种方式的事件处理程序是在全局作用域中执行,因此this的值为window。
var btn = document.getElementById("myBtn");
btn.onclick = function() {
console.log(window.event.srcElement === this); // true
}
btn.attachEvent("onclick", function(event) {
console.log(event.srcElement === this); // false
});
以上がJavaScript イベント学習におけるイベント ストリーム、ハンドラー、オブジェクトの概要の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。