[英]jQuery .on() delegation with selector that matches nested elements
// Example A $("#delegate").on("click", function(event) { // executes on click on any descendant of #delegate or self (not a delegate at all) // 'this' is #delegate }); // Example B $("#delegate").on("click", "#outer", function(event) { // executes on click on any descendant of #outer or self // 'this' is #outer or #inner (depends on the actual click) }); $("#delegate").on("click", "#inner", function(event) { // executes on click on any descendant of #inner or self (nothing happens when clicking #outer) // 'this' is #inner }); // Example C (now it's getting weird) $("#delegate").on("click", "div", function(event) { // executes twice, when clicking #inner, because the event passes #outer when bubbling up // one time 'this' is #inner, and the other time 'this' is #outer // stopPropagation() // actually prevents the second execution });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="delegate"> <div id="outer"> outer <div id="inner"> inner </div> </div> </div>
你如何從邏輯上解釋這種行為?
只有一個點擊事件,從#inner
開始,通過#outer
,最后到達#delegate
。
該事件由#delegate
的 on-handler #delegate
(恰好)一次。 處理程序檢查事件的歷史記錄是否包含任何 div 元素。
如果這適用,回調函數應該被調用一次。 這就是我所期望的。 “單個事件、單個處理程序、單個條件、單個回調”。
如果您查看stopPropagation()
行為,它會變得更加瘋狂。 您實際上可以避免第二次執行,盡管事件已經到達#delegate
。 stopPropagation(
不應該在這里工作。
在委托邏輯的實現中做了什么樣的“魔法”? 事件冒泡和程序流是否以任何方式分開?
請不要首先發布“實用建議”(“請改用 xyz!”)。 我想了解為什么代碼的工作方式如此。
由於您以兩種方式在所有 div 上綁定事件:
所以如果你event.stopPropagation();
在最后一個警報仍然會出現兩次,因為您點擊了 div 和#inner
(例如)。
檢查下面的片段。
$("#delegate").on("click", function(event) { alert(this.id); }); /* $("#delegate").on('click', "#outer", function(event) { alert(this.id); }); $("#delegate").on('click', "#inner", function(event) { alert(this.id); }); */ // now it's getting weird $("#delegate").on("click", "div", function(event) { event.stopPropagation(); alert(this.id); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="delegate"> <div id="outer"> outer <div id="inner"> inner </div> </div> </div>
事件委托的工作方式是 jQuery 從最里面的目標到委托綁定的元素沿着 DOM 樹向上走,測試每個元素以查看它是否與選擇器匹配。 如果是,則執行將this
綁定到該元素的處理程序。
當event.stopPropagation
被調用時,它會在event
對象中設置一個標志。 遍歷 DOM 樹的循環也調用event.isPropagationStopped()
。 如果傳播停止,它就會跳出循環。
換句話說,jQuery 在實現委托時正在做自己的冒泡和傳播停止,它沒有利用瀏覽器的冒泡(除了這種冒泡是在#delegate
上觸發初始事件所#delegate
,因此 jQuery 循環將跑)。
一切都按預期工作。 看看這個小提琴:
$("#delegate").on("click", "div", function(event) {
// event.stopPropagation();
alert('div: ' + $(this).attr('id'));
});
單擊#inner
將觸發上述事件。 該事件將氣泡高達#outer
因為#inner
是的后代#outer
。 由於#outer
也是一個<div
,事件也將在#outer
上#outer
。 從邏輯上講,點擊#inner
將首先提示“div:inner”,然后是“div:outer”。
調用event.stopPropagation()
告訴事件不要冒泡,因此#outer
保持未#outer
狀態。
除了這個小提琴:
<div id="delegate">
<div id="first">
first
</div>
<div id="second">
second
<div id="third">
third, inside second
</div>
</div>
</div>
點擊第三個將首先提醒third
,然后second
然后停止,因為#first
不是父級而是兄弟級。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.