对jquery监听器如何工作感到困惑

时间:2013-11-21 09:30:19

标签: jquery dom dynamic event-listener

我有一些代码可以动态地添加到DOM的链接,并为每个链接添加侦听器。我遇到的问题是,每次我点击其中一个链接时,所有处理程序都会触发。我尝试修复此问题,结果总是这样或者我根本没有得到任何响应(好像从未分配过监听器)。

所以我只是通过做一些我认为不起作用的事情来解决问题。我将侦听器分配给动态添加的元素的id(而不是将其分配给DOM中已有的父元素)。我认为这是不可能的,因为监听器必须在DOM中已经存在的元素上?

让我更加困惑的是,我在jsfiddle中使用了一些非常相似的代码,其结果几乎与我得到的相反。当我遇到问题时,它工作正常,当我解决了我的问题时,解决方案在jsfiddle中无效!

所以这是我的工作代码。更多背景 - 我正在使用Firebase,并且每次在DB中发生child_added事件时都会添加这些li元素(或者当用户登录时,列表将填充数据库中已有的所有条目)。 / p>

var songName = songSnapshot.name();
$(listSelector).append("<li id='" + songName + "'><a href='#'>" + songName + "</a></li>");
$("#" + songName).on("click", function(event) {
  event.preventDefault();
  var clickedSong = $(this).text();
  loadCheck(clickedSong);
});

这是HTML:

  <ul class="six columns" id="dropdowns">
    <li><a href="#" id="createsong">Create New Song</a></li>
    <li>
      <a href="#">Your Songs</a>
      <div class="dropdown">
        <ul id="userSonglist">

        </ul>
      </div>
    </li>
    <li>
      <a href="#">All Songs</a>
      <div class="dropdown">
        <ul id="publicSonglist">

        </ul>
      </div>
    </li>
  </ul>

任何想法发生了什么,为什么这有效?我对jquery侦听器的理解不正确吗?我花了整整一天时间在jquery.com和其他网站上研究这个问题,但这仍然让我感到困惑。我实际上只是在jsfiddle中尝试了这个代码,它起作用了。所以很明显我错过了/误解了什么。

3 个答案:

答案 0 :(得分:2)

我会做的是这样......

// P.s. this if/else statement are doing the exact same thing?!
var songName = songSnapshot.name();
if (listSelector === "#publicSonglist") {
  $(listSelector).append("<li id='" + songName + "' class='songItem'><a href='#'>" + songName + "</a></li>");
}
else {
  $(listSelector).append("<li id='" + songName + "' class='songItem'><a href='#'>" + songName + "</a></li>");
};

然后,在您的点击/添加事件之外:

$('#dropdowns').on("click", '.songItem', function(event) {
  event.preventDefault();
  var clickedSong = $(this).text();
  loadCheck(clickedSong);
});

答案 1 :(得分:1)

你有什么误解?你的代码非常好。

var songName = songSnapshot.name();
if (listSelector === "#publicSonglist") {
  $(listSelector).append("<li id='" + songName + "'><a href='#'>" + songName + "</a></li>");
}
else {
  $(listSelector).append("<li id='" + songName + "'><a href='#'>" + songName + "</a></li>");
};

此时元素已添加到dom中,因此您可以实际将事件绑定到它。即使它没有添加到dom中,您也可以使用jQuery on()选择父级使用事件委派:

  

委派事件的优势在于它们可以处理来自的事件   稍后添加到文档中的后代元素。

所以你会做类似的事情:

$('#dropdowns').on("click", '#'+songName, function(event) {
  event.preventDefault();
  var clickedSong = $(this).text();
  loadCheck(clickedSong);
});

或者甚至更慷慨,因为你根本不需要id:

$('#dropdowns').on("click", '.songItem', function(event) {
  event.preventDefault();
  var clickedSong = $(this).text();
  loadCheck(clickedSong);
});

希望能帮助您理解:)

答案 2 :(得分:1)

感谢您提出这样一个全面的问题,进一步回答当前的答案:


动态DOM

JQuery建立在Javascript之上,因此您的问题不仅仅是JQuery的

这两种技术的工作方式是采用文件和文件的要素。在加载时为它们分配函数。这意味着加载后添加的任何元素都必须动态分配eventListener / function

您遇到的问题是您的元素没有绑定到它们的函数,因为当JS分配其函数/侦听器时它们不存在。这意味着,无论元素添加过程如何,您都必须能够在添加事件时将事件绑定到新元素:


Event Delegation

您的修复的正确术语是“委派”您的JS事件

委托基本上意味着JS不会监听特定元素,而是实际监听父元素,然后将其功能“委托”给它的所有子元素。这意味着如果动态添加子项,事件仍将捕获它们

这里有一些代码:

$("#dropdowns").on("click", "li", function(event) {
  event.preventDefault();
  var clickedSong = $(this).text();
  loadCheck(clickedSong);
});

正如您所看到的,委派事件的典型方法是将其放在父元素上,但您也可以始终附加到$(document)(因为这是页面的整体父级)