この章では、JavaScript イベント ストリーム イベントとは何なのかについて説明します。 (はじめに) を参照して、JavaScript イベントとイベント ストリームが何であるかを誰もが理解できるようにします。困っている友人は参考にしていただければ幸いです。
1. JavaScript イベント
イベントは、ドキュメントまたはブラウザ ウィンドウで発生する対話の特定の瞬間です。
イベントとは、ユーザーまたはブラウザ自体によって実行される特定のアクションです。クリック、ロード、マウスオーバーなどはイベントの名前です。
イベントは、JavaScript と DOM の間の架け橋です。
あなたがトリガーした場合は、それを実行します。イベントが発生すると、そのハンドラー関数が呼び出され、対応する JavaScript コードが実行され、応答が返されます。
典型的な例としては、load イベントはページが読み込まれるときにトリガーされ、click イベントはユーザーが要素をクリックしたときにトリガーされます。
2. イベント フロー
イベント フローは、ページからイベントを受け取る順序を記述します。
1. イベント インフルエンザの認識
質問: ページ要素をクリックすると、どのような要素がそのようなイベントを感知しますか?
回答: 要素をクリックすると、その要素のコンテナ要素、またはページ全体もクリックされることになります。
例: 3 つの同心円があり、各円に対応するイベント処理関数を追加し、対応するテキストをポップアップします。一番内側の円をクリックすると外側の円もクリックされるため、外側の円のクリックイベントもトリガーされます。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <style> #outer{ position: absolute; width: 400px; height: 400px; top:0; left: 0; bottom:0; right: 0; margin: auto; background-color: deeppink; } #middle{ position: absolute; width: 300px; height:300px; top:50%; left: 50%; margin-left: -150px; margin-top: -150px; background-color: deepskyblue; } #inner{ position: absolute; width: 100px; height:100px; top:50%; left:50%; margin-left: -50px; margin-top: -50px;; background-color: darkgreen; text-align: center; line-height: 100px; color:white; } #outer,#middle,#inner{ border-radius:100%; } </style> <body> <div id="outer"> <div id="middle"> <div id="inner"> click me! </div> </div> </div> <script> var innerCircle= document.getElementById("inner"); innerCircle.onclick= function () { alert("innerCircle"); }; var middleCircle= document.getElementById("middle"); middleCircle.onclick=function(){ alert("middleCircle"); } var outerCircle= document.getElementById("outer"); outerCircle.onclick= function () { alert("outerCircle"); } </script> </body> </html>
レンダリング:
2. イベント フロー
イベントが発生すると、要素ノードとルート ノードの間で特定の順序で伝播されます。この伝播プロセスは DOM イベント ストリームです。
1) 2 つのイベント フロー モデル
イベントの伝播の順序は、ブラウザーの 2 つのイベント フロー モデル (キャプチャ イベント フローとバブリング イベント フロー) に対応します。
バブル イベント フロー : イベントの伝播は、最も具体的なイベント ターゲットから最も具体性の低いイベント ターゲットまで行われます。つまり、DOM ツリーの葉から根までです。 [推奨事項]
キャプチャ型イベント フロー: イベントの伝播は、最も具体性の低いイベント ターゲットから最も具体性の高いイベント ターゲットまで行われます。つまり、DOM ツリーのルートから葉までです。
イベント キャプチャの考え方は、特定性の低いノードがイベントをより早く受信し、最も特定性の高いノードが最後にイベントを受信するというものです。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="myDiv">Click me!</div> </body> </html>
上記の HTML コードでは、ページ内の
バブリング イベント ストリーム内のクリック イベントの伝播順序は
キャプチャ イベント ストリームでは、クリック イベントの伝播順序は document—>>—>>
—>>注:
最新のブラウザはすべてイベント バブリングをサポートしていますが、特定の実装には若干の違いがあります:
IE5 .5 以前のバージョンでは、イベント バブリングは 要素をスキップします (本文からドキュメントに直接ジャンプします)。
IE9、Firefox、Chrome、Safari では、イベントがウィンドウ オブジェクトに至るまでバブルされます。
2)、IE9、Firefox、Chrome、Opera、Safari はすべてイベント キャプチャをサポートしています。 DOM 標準ではイベントがドキュメント オブジェクトから伝播される必要がありますが、これらのブラウザはウィンドウ オブジェクトからイベントをキャプチャします。
3) 古いバージョンのブラウザではサポートされていないため、イベント キャプチャを使用する人はほとんどいません。イベントバブリングを使用することをお勧めします。
2) DOM イベント フロー
DOM 標準ではキャプチャ バブリングが採用されています。どちらのイベント ストリームも、ドキュメント オブジェクトで始まりドキュメント オブジェクトで終わる DOM 内のすべてのオブジェクトをトリガーします。
DOM 標準では、イベント フローにはイベント キャプチャ ステージ、ターゲット ステージ、イベント バブリング ステージの 3 つのステージが含まれると規定されています。
イベント キャプチャ フェーズ: 実際のターゲット (
はターゲット ステージにあり、イベントが発生し、
バブリングフェーズ: イベントがドキュメントに伝播されます。 ############注記:###
尽管“DOM2级事件”标准规范明确规定事件捕获阶段不会涉及事件目标,但是在IE9、Safari、Chrome、Firefox和Opera9.5及更高版本都会在捕获阶段触发事件对象上的事件。结果,就是有两次机会在目标对象上面操作事件。
并非所有的事件都会经过冒泡阶段 。所有的事件都要经过捕获阶段和处于目标阶段,但是有些事件会跳过冒泡阶段:如,获得输入焦点的focus事件和失去输入焦点的blur事件。
两次机会在目标对象上面操作事件例子:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <style> #outer{ position: absolute; width: 400px; height: 400px; top:0; left: 0; bottom:0; right: 0; margin: auto; background-color: deeppink; } #middle{ position: absolute; width: 300px; height:300px; top:50%; left: 50%; margin-left: -150px; margin-top: -150px; background-color: deepskyblue; } #inner{ position: absolute; width: 100px; height:100px; top:50%; left:50%; margin-left: -50px; margin-top: -50px;; background-color: darkgreen; text-align: center; line-height: 100px; color:white; } #outer,#middle,#inner{ border-radius:100%; } </style> <body> <div id="outer"> <div id="middle"> <div id="inner"> click me! </div> </div> </div> <script> var innerCircle= document.getElementById("inner"); innerCircle.addEventListener("click", function () { alert("innerCircle的click事件在捕获阶段被触发"); },true); innerCircle.addEventListener("click", function () { alert("innerCircle的click事件在冒泡阶段被触发"); },false); var middleCircle= document.getElementById("middle"); middleCircle.addEventListener("click", function () { alert("middleCircle的click事件在捕获阶段被触发"); },true); middleCircle.addEventListener("click", function () { alert("middleCircle的click事件在冒泡阶段被触发"); },false); var outerCircle= document.getElementById("outer"); outerCircle.addEventListener("click", function () { alert("outerCircle的click事件在捕获阶段被触发"); },true); outerCircle.addEventListener("click", function () { alert("outerCircle的click事件在冒泡阶段被触发"); },false); </script> </body> </html>
运行效果就是会陆续弹出6个框,为说明原理我整合成了一个图:
3、事件流的典型应用事件代理
传统的事件处理中,需要为每个元素添加事件处理器。js事件代理则是一种简单有效的技巧,通过它可以把事件处理器添加到一个父级元素上,从而避免把事件处理器添加到多个子级元素上。
1)事件代理
事件代理的原理用到的就是事件冒泡和目标元素,把事件处理器添加到父元素,等待子元素事件冒泡,并且父元素能够通过target(IE为srcElement)判断是哪个子元素,从而做相应处理。关于target更多内容请参考javaScript事件(四)event的公共成员(属性和方法) 下面举例来说明。
传统事件处理,为每个元素添加事件处理器,代码如下:
<body> <ul id="color-list"> <li>red</li> <li>orange</li> <li>yellow</li> <li>green</li> <li>blue</li> <li>indigo</li> <li>purple</li> </ul> <script> (function(){ var colorList=document.getElementById("color-list"); var colors=colorList.getElementsByTagName("li"); for(var i=0;i<colors.length;i++) { colors[i].addEventListener('click',showColor,false); }; function showColor(e) { e=e||window.event; var targetElement=e.target||e.srcElement; alert(targetElement.innerHTML); } })(); </script> </body>
事件代理的处理方式,代码如下:
<body> <ul id="color-list"> <li>red</li> <li>orange</li> <li>yellow</li> <li>green</li> <li>blue</li> <li>indigo</li> <li>purple</li> </ul> <script> (function(){ var colorList=document.getElementById("color-list"); colorList.addEventListener('click',showColor,false); function showColor(e) { e=e||window.event; var targetElement=e.target||e.srcElement; if(targetElement.nodeName.toLowerCase()==="li"){ alert(targetElement.innerHTML); } } })(); </script> </body>
2)事件代理的好处
总结一下事件代理的好处:
将多个事件处理器减少到一个,因为事件处理器要驻留内存,这样就提高了性能。想象如果有一个100行的表格,对比传统的为每个单元格绑定事件处理器的方式和事件代理(即table上添加一个事件处理器),不难得出结论,事件代理确实避免了一些潜在的风险,提高了性能。
DOM更新无需重新绑定事件处理器,因为事件代理对不同子元素可采用不同处理方法。如果新增其他子元素(a,span,div等),直接修改事件代理的事件处理函数即可,不需要重新绑定处理器,不需要再次循环遍历。
3)事件代理的问题:【update20170502】
代码如下:事件代理同时绑定了li和span,当点击span的时候,li和span都会冒泡。
<li><span>li中的span的内容</span></li> <script> $(document).on('click', 'li', function(e){ alert('li li'); }); $(document).on('click', 'span', function(e){ alert('li span'); }) </script>
解决办法:
方法一:span的事件处理程序中阻止冒泡
$(document).on('click', 'span', function(e){ alert('li span'); e.stopPropagation(); })
方法二:li的事件处理程序中检测target元素
$(document).on('click', 'li', function (e) { if (e.target.nodeName == 'SPAN') { e.stopPropagation(); return; } alert('li li'); });
4)事件代理的一个有趣应用【update20170502】
点击一个列表时,输出对应的索引
<script> var ul=document.querySelector('ul'); var lis=ul.querySelectorAll('ul li'); ul.addEventListener('click', function (e) { var target= e.target; if(target.nodeName.toUpperCase()==='LI'){ alert([].indexOf.call(lis,target)); } },false) </script>
以上がJavaScript イベント ストリーム イベントとは何ですか? (導入)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。