ホームページ > 記事 > ウェブフロントエンド > イベントバブリングとJavaScriptイベントの時間キャプチャ(サマリー共有)
この記事では、イベントバブリングや時間キャプチャなど、JavaScriptのイベントに関する基礎知識を詳しく解説していますので、皆様のお役に立てれば幸いです。
Web ページ上の要素 (p 要素など) をクリックしたとき。よく考えてみると、このp要素だけでなく、その要素の親、外側のボディ、ボディの親要素html、外部要素のレイヤードキュメント。これらの入れ子になった要素間でのイベントの伝播は、イベント フローと呼ばれます。
IEのイベントストリームはイベントと呼ばれます。最も具体的な要素から始まり、上向きに伝播します。 DOM0 を使用して追加したイベント ハンドラーは、イベント バブリング段階で処理されます。例:
<html> <head> <script type="text/javascript"> window.onload = bubblingHandle; function bubblingHandle() { //内层p处理程序 document.getElementById("inner").onmousedown = function() { alert("inner p"); } //外层p处理程序 document.getElementById("outer").onmousedown = function() { alert("outerp"); } document.onmousedown = function() { alert("document"); } } --> </script> </head> <body> <p id="outer" style="background-color:black; padding: 15px;"> <p id="inner" style="background-color:white; padding: 5px;"></p> </p> </body></html>
内層の白いpをクリックすると、順番に表示されます:
inner p outer p document
イベントキャプチャ
イベントフローNetscape が提案したものはイベント キャプチャと呼ばれ、IE とはほぼ逆です。イベントは最初に最も具体性の低い要素によって受信され、次に特定のノードに伝播されます。
イベントは、WEB ページ内で発生する特定の動作によってトリガーされます。たとえば、ページ要素上でマウスの左ボタンを押すか、キーボードのキーを押すか、オブジェクトがフォーカスを取得または失うと、対応するイベントがトリガーされます。 JavaScript と HTML 間の対話は、イベントを通じて実現されます。イベント リスナーを使用してイベントを「登録」し、イベントが発生すると対応するコードが実行されます。
DOM レベル 0 イベント ハンドラーは、そのシンプルさとクロスブラウザーのサポートにより、引き続きすべてのブラウザーでサポートされます。
があります。)この方法で追加されたイベント ハンドラーは、イベント フローのバブリング フェーズ中に処理されることに注意してください。 イベント ハンドラー属性に関しては、次の点を説明する必要があります:
1. イベント ハンドラー属性はすべて小文字で、「on」で始まり、その後にイベント タイプが続きます:
onclick //单击鼠标 onload //图像或页面载入完成 onmouseover //将鼠标移动到某元素上面 onmousemove //移动鼠标 onfocus //对象获得焦点
2. img、a、input、window や document を含む form などの各要素は、独自のイベント ハンドラー属性を持ちます。例:
document.getElementById("btn1").onclick //btn1上单击鼠标 document.getElementById("img1").onmouseover //鼠标移动到img1 document.getElementById("img1").onmerror //img1图像无法载入
次に、イベント ハンドラー属性に値を割り当てて、イベント ハンドラー メソッドの指定を完了します。たとえば、マウスを「img1」に移動すると、「これは素晴らしい写真です!」というダイアログ ボックスが表示されます。
var pic1 = document.getElementById("img1"); pic1.onmouseover = function() { alert("This is a nice pic!"); };
特記事項: 上記のコードがドキュメントの最後にある場合、ページがロードされたばかりなので、img1 の上にマウスを移動します。コードがまだ実行されていないため、設定したダイアログ ボックスがポップアップしない可能性があります。現在では、この遅延は非常に短くなりました。イベントハンドラの
This
は、DOM0 レベルのメソッドで指定されたイベント ハンドラであり、
要素メソッド6c62a7e2513a7465a5a873220f3f5dac ...//省略 8019067d09615e43c7904885b5246f0a 89e3bb261a36e34e3f1c9a90f67afd83 2cacc6d41bbb37262a98f745aa00fbf0
DOM0 レベルのメソッドによるイベント ハンドラーの削除イベント ハンドラーを削除するには、対応するイベント ハンドラー属性を null に設定するだけです:
pic1.onmouseover = null;
##現在、ほとんどすべてのブラウザが DOM0 イベント モデルをサポートしていますが、開発者は新しい DOM2 モデルを使用することをお勧めします。 DOM2 モデルと DOM0 の間には 2 つの大きな違いがあります:
1. DOM2 はイベント ハンドラー属性に依存しません2. 1 つのイベントの同じイベントに対して複数のハンドラーを登録できます。オブジェクトを同時に登録しますので、登録順序に従ってください。addEventListener() //指定事件处理程序 removeEventListener() //删除事件处理程序
6c62a7e2513a7465a5a873220f3f5dac ... 8019067d09615e43c7904885b5246f0a 0e82aacda029e768165406ce66a9f59e 2cacc6d41bbb37262a98f745aa00fbf0
btn1 ボタンをクリックすると、ダイアログ ボックスが順に表示されます:
handle1! handle2!
removeEventListener() メソッドを使用して、指定したイベント ハンドラーを削除できます。一貫性のあるパラメータに注意してください:
btn1.removeEventListener("click", handle2, false);
この時点で btn1 ボタンをクリックすると、handle1! のみが表示されます。
匿名関数を使用してイベント ハンドラーを指定する場合、removeEventListener() メソッドを使用してイベント ハンドラーを削除できないことに注意することが重要です。
btn1.addEventListener("click", function(){ alert("click!"); }, false); btn1.removeEventListener("click", function(){ alert("click!"); }, false); //无法取消!
这样是无法取消以上指定的事件处理程序的!因为上面addEventListener和removeEventListener中的2个事件处理函数虽然代码相同,实质上是2个不同的函数引用。
另外,强调一点,以上两个函数的第一个参数(要处理的事件名)是没有on前缀的。这一点和IE不同,后面会说明。
tips: IE9, Firefox, Safari, Chrome以及Opera均支持DOM2级事件处理程序。
DOM2事件处理程序和DOM0相同,它们的this都在其依附的元素作用域中运行。this的指代参考DOM0的示例。这里之所以要特别指出DOM2的this,是为了和IE事件处理程序进行区分。IE中事件处理程序this与事件指定方式有关。
IE并没有提供对W3C事件模型的支持,其实现了2个和DOM2模型类似的方法:
attachEvent() detachEvent()
这两个方法只接收2个参数:事件名称以及事件处理函数。由于IE8及更早版本只支持事件冒泡,这两个方法添加的事件处理程序会在事件冒泡阶段被执行。
和DOM2不同的是:
例如:
6c62a7e2513a7465a5a873220f3f5dac ... 8019067d09615e43c7904885b5246f0a 84f07fc1f7167f067b3f15a898dda831 2cacc6d41bbb37262a98f745aa00fbf0
执行结果:
handle2! true handle1! true
虽然可以使用屏蔽浏览器差异的JS库,实际上,我们自己编写一个跨浏览器兼容的事件处理代码并不是一件困难的事情,同时更有利于我们对原生JavaScript的学习理解。我们使用一个习惯上称为EventUtil的对象来进行跨浏览器事件处理:
var EventUtil = { addEventHandler : function(element, eventType, handler) { if(element.addEventListener){ element.addEventListener(eventType, handler, flase); } else if(element.attachEvent) { element.attachEvent("on" + eventType, handler); } else { element["on" + eventType] = handler; } }, removeEventHandler : function(element, eventType, handler) { if(element.aremoveEventListener){ element.addEventListener(eventType, handler, flase); } else if(element.detachEvent) { element.attachEvent("on" + eventType, handler); } else { element["on" + eventType] = null; } } }
为了保证事件处理代码能够在大多数浏览器中一致地运行,我们这里只关注冒泡阶段。以上代码使用浏览器能力检测,首先检测是否支持DOM2级方法addEventListener和removeEventListener,如果支持则使用该方法;如果不支持该方法,检测是否是IE8级更早版本的attachEvent或detachEvent方法,若支持则使用该方法;如果对以上2种方法都不支持,则使用DOM0级方法。要注意,DOM0级对每个事件只能指定一个事件处理程序。
以上对象使用示例如下:
var btn1 = document.getElementById("btn1");var handle1 = function() { alert("handle1!" + "\n" + (this === window)); };var handle2 = function() { alert("handle2!"+ "\n" + (this === window)); }; EventUtil.addEventHandler(btn1, "click", handler1); EventUtil.addEventHandler(btn1, "click", handler2); EventUtil.removeEventHandler(btn1, "click", handler2);
在触发某个事件时,会产生一个event对象。该对象中包含与事件有关的信息。例如触发事件的元素、事件的类型、与特定事件相关的如鼠标位置信息等。
不论使用DOM0级还是DOM2级方法指定事件处理程序,事件触发时都会自动将一个event对象传入事件处理程序,例如:
var btn1 = document.getElementById("btn1"); btn1.onmouseover = function(evnt) { alert(evnt.type); }var handle = function(evnt) { alert(evnt.type); }; btn1.addEventListener("click", handle, false);
以上是一个简单的event对象的示例。event对象中的type属性是一个只读字符串属性,其中包含着事件的类型。例如我们上例中的click和onmouseover。event对象中包含有大量的有关事件的属性和方法(例如event.stopPropagation()方法可用于停止事件在捕获或者冒泡阶段的继续传播,preventDefault()方法会取消阻止事件的行)在此就不一一列举了。其中常用的如下:
属性/方法 | 值类型 | 读写 | 描述 |
---|---|---|---|
currentTarget | Element | readonly | 事件处理程序当前正在处理的元素 |
target | Element | readonly | 事件的目标 |
type | String | readonly | 触发事件的类型 |
preventDefault | Function | readonly | 取消事件默认行为,如链接的默认行为就是被单击时跳转到href指定的url |
stopPropagation | Function | readonly | 取消事件进一步冒泡或捕获 |
在IE中,当使用DOM0级指定事件处理程序时,event对象被认为是window的一个属性,例如获取鼠标点击坐标的代码:
var mouseLoc = function() { var loc = "x: " + window.event.screenX + "\n" + "y: " + window.event.screenY; alert(loc); };
当使用attachEvent()方法指定事件处理程序时,event对象会被作为参数传入事件处理程序,我们将以上的代码重写:
var mouseLoc = function(event) { var loc = "x: " + event.screenX + "\n" + "y: " + event.screenY; alert(loc); }; btn1.attachEvent("onclick", mouseLoc);
IE中event对象的相关属性方法:
属性/方法 | 值类型 | 读写 | 描述 |
---|---|---|---|
cancelBubble | Boolean | read/write | 默认为false,置为true时取消事件冒泡(同DOM中stopPropagation) |
returnValue | Boolean | read/write | 默认为true,设为false取消事件默认行为(同DOM中preventDefault) |
srcElement | Element | readonly | 事件目标 |
type | String | readonly | 事件类型 |
解决跨浏览器问题的思路是一贯的,我们可以对浏览器进行能力检测,这里我们对上面的EventUtil对象进行扩展,对我们学习原生JS,这是一个很漂亮的对象:
var EventUtil = { addEventHandler : function(element, eventType, handler) { if(element.addEventListener){ element.addEventListener(eventType, handler, flase); } else if(element.attachEvent) { element.attachEvent("on" + eventType, handler); } else { element["on" + eventType] = handler; } }, removeEventHandler : function(element, eventType, handler) { if(element.aremoveEventListener){ element.addEventListener(eventType, handler, flase); } else if(element.detachEvent) { element.attachEvent("on" + eventType, handler); } else { element["on" + eventType] = null; } }, getEvent: function (event) { return event ? event : window.event; }, getTarget: function (event) { return event.target || event.srcElement; }, preventDefault: function (event) { if (event.preventDefault) { event.preventDefault(); } else { event.returnValue = false; } }, stopPropagation: function (event) { if (event.stopPropagation) { event.stopPropagation(); } else { event.cancelBubbles = true; } }, getRelatedTarget: function (event) { if (event.relatedTarger) { return event.relatedTarget; } else if (event.toElement) { return event.toElement; } else if (event.fromElement) { return event.fromElement; } else { return null; } } }
【相关推荐:javascript学习教程】
以上がイベントバブリングとJavaScriptイベントの時間キャプチャ(サマリー共有)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。