この記事では主に Javascript イベントバブリングメカニズムの詳細な導入に関する関連情報を紹介しますので、必要な方は参考にしてください
1. イベント
ブラウザクライアントアプリケーションプラットフォームでは、基本的にすべてがイベント駆動です。 、イベントが発生し、対応するアクションが実行されます。
ブラウザ イベントは、何かが起こったという信号を表します。イベントの詳細については、この記事の焦点ではありません。まだ理解していない人は、W3school チュートリアルにアクセスして、次の内容をより深く理解することができます。
2.バブルの仕組み
バブリングとは?
下の写真を見てわかると思いますが、泡は水の底から始まり、深いところから浅いところまで上がっていきます。上昇する途中で、泡はさまざまな深さの水中を通過します。
これに対応して: このバブルはここでのイベントに相当し、水は dom ツリー全体のイベントに相当し、イベントは dom ツリーの最下位層から dom ツリーのルート ノードに渡されるまで渡されます。ドム。
簡単なケース分析
以下はバブリングの原理を示す簡単な例です:
3 つの単純な dom 要素を含む HTML を定義します: p1、p2、span、p2 には span が含まれ、p1 には p2 が含まれます。すべて本文の下にあります:
<body id="body"> <p id="box1" class="box1"> <p id="box2" class="box2"> <span id="span">This is a span.</span> </p> </p> </body>
インターフェースのプロトタイプは次のとおりです:
イベントがキャプチャされると、インシデントの時刻とトリガーイベントのノード情報が出力されます: R
<script type="text/javascript"> window.onload = function() { document.getElementById("body").addEventListener("click",eventHandler); } function eventHandler(event) { console.log("时间:"+new Date(event.timeStamp)+" 产生事件的节点:" + event.target.id +" 当前节点:"+event.currentTarget.id); } </script>
一般的に、イベントは伝達中にいくつかの情報を持ち、これらはイベントの構成部分です: イベントが発生したもの時間+イベント発生場所+イベントの種類+イベントの現在のハンドラーとその他の情報、
完全な HTML コードは次のとおりです:Insert title here <script type="text/javascript"> window.onload = function() { document.getElementById("body").addEventListener("click",eventHandler); } function eventHandler(event) { console.log("时间:"+new Date(event.timeStamp)+" 产生事件的节点:" + event.target.id +" 当前节点:"+event.currentTarget.id); } </script> <body id="body"> <p id="box1" class="box1"> <p id="box2" class="box2"> <span id="span">This is a span.</span> </p> </p> </body>
b. イベントのバブリングを終了します
ここで、p1 が次のような関数を実装したいとします。 p2 をクリックすると、「こんにちは、私は一番外側の p です。」が表示されます。span をクリックすると、「こんにちは、私はスパンです。」が表示されます。 これにより、次の JavaScript フラグメントが得られます:
<script type="text/javascript"> window.onload = function() { document.getElementById("box1").addEventListener("click",function(event){ alert("您好,我是最外层p。"); }); document.getElementById("box2").addEventListener("click",function(event){ alert("您好,我是第二层p。"); }); document.getElementById("span").addEventListener("click",function(event){ alert("您好,我是span。"); }); } </script>
上記のコードが「span」をクリックすると、「こんにちは、私は span です。」というポップアップ ボックスが表示されます。いいえ、このダイアログ ボックスだけでなく、[OK] をクリックすると、次のダイアログ ボックスが順番に表示されます:
这显然不是我们想要的! 我们希望的是点谁显示谁的信息而已。为什么会出现上述的情况呢? 原因就在于事件的冒泡,点击span的时候,span 会把产生的事件往上冒泡,作为父节点的p2 和 祖父节点的p1也会收到此事件,于是会做出事件响应,执行响应函数。现在问题是发现了,但是怎么解决呢?
方法一:我们来考虑一个形象一点的情况:水中的一个气泡正在从底部往上冒,而你现在在水中,不想让这个气泡往上冒,怎么办呢?——把它扎破!没了气泡,自然不会往上冒了。类似地,对某一个节点而言,如果不想它现在处理的事件继续往上冒泡的话,我们可以终止冒泡:
在相应的处理函数内,加入 event.stopPropagation() ,终止事件的广播分发,这样事件停留在本节点,不会再往外传播了。修改上述的script片段:
<script type="text/javascript"> window.onload = function() { document.getElementById("box1").addEventListener("click",function(event){ alert("您好,我是最外层p。"); event.stopPropagation(); }); document.getElementById("box2").addEventListener("click",function(event){ alert("您好,我是第二层p。"); event.stopPropagation(); }); document.getElementById("span").addEventListener("click",function(event){ alert("您好,我是span。"); event.stopPropagation(); }); } </script>
经过这样一段代码,点击不同元素会有不同的提示,不会出现弹出多个框的情况了。
方法二:事件包含最初触发事件的节点引用 和 当前处理事件节点的引用,那如果节点只处理自己触发的事件即可,不是自己产生的事件不处理。event.target 引用了产生此event对象的dom 节点,而event.currrentTarget 则引用了当前处理节点,我们可以通过这 两个target 是否相等。
比如span 点击事件,产生一个event 事件对象,event.target 指向了span元素,span处理此事件时,event.currentTarget 指向的也是span元素,这时判断两者相等,则执行相应的处理函数。而事件传递给 p2 的时候,event.currentTarget变成 p2,这时候判断二者不相等,即事件不是p2 本身产生的,就不作响应处理逻辑。
<script type="text/javascript"> window.onload = function() { document.getElementById("box1").addEventListener("click",function(event){ if(event.target == event.currentTarget) { alert("您好,我是最外层p。"); } }); document.getElementById("box2").addEventListener("click",function(event){ if(event.target == event.currentTarget) { alert("您好,我是第二层p。"); } }); document.getElementById("span").addEventListener("click",function(event){ if(event.target == event.currentTarget) { alert("您好,我是span。"); } }); } </script>
比较:
从事件传递上看:方法一在于取消事件冒泡,即当某些节点取消冒泡后,事件不会再传递;方法二在于不阻止冒泡,过滤需要处理的事件,事件处理后还会继续传递;
优缺点:
方法一缺点:为了实现点击特定的元素显示对应的信息,方法一要求每个元素的子元素也必须终止事件的冒泡传递,即跟别的元素功能上强关联,这样的方法会很脆弱。比如,如果span 元素的处理函数没有执行冒泡终止,则事件会传到p2 上,这样会造成p2 的提示信息;
方法二缺点:方法二为每一个元素都增加了事件监听处理函数,事件的处理逻辑都很相似,即都有判断 if(event.target == event.currentTarget),这样存在了很大的代码冗余,现在是三个元素还好,当有10几个,上百个又该怎么办呢?
还有就是为每一个元素都有处理函数,在一定程度上增加逻辑和代码的复杂度。
我们再来分析一下方法二:方法二的原理是 元素收到事件后,判断事件是否符合要求,然后做相应的处理,然后事件继续冒泡往上传递; 既然事件是冒泡传递的,那可不可以让某个父节点统一处理事件,通过判断事件的发生地(即事件产生的节点),然后做出相应的处理呢?答案是可以的,下面通过给body 元素添加事件监听,然后通过判断event.target 然后对不同的target产生不同的行为。
将方法二的代码重构一下:
<script type="text/javascript"> window.onload = function() { document.getElementById("body").addEventListener("click",eventPerformed); } function eventPerformed(event) { var target = event.target; switch (target.id) { case "span": alert("您好,我是span。"); break; case "p1": alert("您好,我是第二层p。"); break; case "p2": alert("您好,我是最外层p。"); break; } } </script>
结果会是点击不同的元素,只弹出相符合的提示,不会有多余的提示。
上記のメソッドを通じて、各要素が完了するために必要な処理関数をその親ノードの body 要素に引き渡しました。つまり、span、p2、および p1 がその応答ロジックを body に委任します。このモデルは、いわゆるイベント委任です。
以下は模式図です:
上記は私がまとめたものであり、将来的に皆様のお役に立てば幸いです。
関連記事:
JavaScript Cookieの詳細説明と簡単なアプリケーション例(画像とテキストのチュートリアル)
ネイティブで強力なDOMセレクターquerySelectorの詳細な紹介(コード添付)
数種類のJavaScriptコメントコード 方法 (画像とテキストのチュートリアル)
以上がJavascript イベントバブリングメカニズムの詳細な紹介 (グラフィックチュートリアル)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。