jQuery .on()委托,带有与嵌套元素匹配的选择器

时间:2015-09-11 12:34:27

标签: javascript jquery javascript-events delegation event-bubbling

// 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将事件(确切地)捕获一次。处理程序检查事件的历史记录是否包含任何div元素。

如果适用,则应调用一次回调函数。这就是我所期待的。 “单个事件,单个处理程序,单个条件,单个回调”。

如果你看一下stopPropagation()行为,会变得更加疯狂。尽管事件已经到达#delegate,但你实际上可以避免这种情况。 stopPropagation()不应该在这里工作。

在授权逻辑的实现中做了什么样的“魔术”?事件冒泡和程序流程是否以任何方式分离?

感谢您对德国的解释和问候。 ; - )

请不要首先发布“实用建议”(“使用xyz代替!”)。我想了解为什么代码按照它的方式工作。

3 个答案:

答案 0 :(得分:0)

因为你以两种方式绑定所有div上的事件:

  1. 使用元素div的id属性。
  2. 使用元素div的标记名称。
  3. 所以,如果您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>

答案 1 :(得分:0)

事件委托的工作方式是jQuery将DOM树从最里面的目标移动到委托绑定的元素,测试每个元素以查看它是否与选择器匹配。如果是,则执行绑定到该元素的this处理程序。

调用event.stopPropagation时,它会在event对象中设置一个标志。遍历DOM树的循环也调用event.isPropagationStopped()。如果传播停止,它就会脱离循环。

换句话说,jQuery在实现委托时正在进行自己的冒泡和传播停止,它没有利用浏览器的冒泡(除了这个冒泡对于初始事件是必要的在#delegate上触发,以便jQuery循环运行。)

答案 2 :(得分:0)

一切都按预期工作。看看this fiddle

$("#delegate").on("click", "div", function(event) {
  // event.stopPropagation();
  alert('div: ' + $(this).attr('id'));
});

点击#inner会触发上述事件。由于#outer#inner的后代,因此该事件将冒出#outer。由于#outer也是<div,因此该事件也会在#outer上触发。从逻辑上讲,点击#inner将首先警告&#34; div:inner&#34;然后&#34; div:外部&#34;。

调用event.stopPropagation()告诉事件不要冒泡,因此#outer保持不受欢迎。

除了this fiddle

<div id="delegate">
  <div id="first">
    first
  </div>
  <div id="second">
    second
      <div id="third">
        third, inside second
      </div>
    </div>
</div>

点击第三个会先提醒third,然后提醒second,然后停止,因为#first不是父母,而是兄弟。