Обработчик событий jQuery работает только для первого элемента

Я не могу понять, почему только первый элемент вызывает мой обработчик событий, который отображает предупреждение. Я нашел другие подобные вопросы в Stack Overflow, связанные с использованием идентификаторов, а не классов, но это не моя проблема.

Когда я нажимаю «x» рядом с первым элементом, он отображает предупреждение, как и ожидалось, но не делает этого для других элементов, которые были добавлены динамически с помощью кнопки «Добавить».

Вот минимальный, но полный пример:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>test</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.0/jquery.min.js"></script>
<script type="text/javascript">

$(document).ready(function() {

   $(function() {

     $(".append").click(function(){

      $('.container').append('<div class="box"></div>')
      $('.box:last').append('<div class="text"><span>ABCDEFG</span><br/></div>')
      $('.box:last').append('<a href="#" class="test">x</a>')

     });

      $("a.test").click(function() {
      alert("works only for the first item in the list");


     });


   });


});

</script>
   <style>
      .box {
          padding:3px;
          margin-bottom:3px;
          border-bottom:2px solid #fff;
          width:550px;
      }
      .box:hover{background-color:#fff;}

      #container {
          position:relative;
      }

      .text {
          float:left;
          width:300px;
          font-size:13px;
      }
      .text span {
          font-size:18px;
          line-height:23px;
          font-weight:700;
      }

   </style>
</head>

<body>

   <div class="container">

     <input type="button" class="append" value="Append">

      <div class="box">
     <div class="text"><span>ABCDEFG</span></div>
     <a href="#" class="test">x</a>
     </div>

   </div>

</body>
</html>

person Raj    schedule 27.03.2011    source источник


Ответы (3)


изменять

$("a.test").click(function() {

to

$("a.test").live('click', function() {

Причина, по которой работает только первый элемент, заключается в том, что в момент прикрепления события click на странице присутствует только один элемент <a>. Вам необходимо явно добавить обработчик события щелчка к каждой созданной привязке или вместо этого использовать живые события. Узнайте больше об обработчиках событий live.

person Anurag    schedule 27.03.2011
comment
Это было именно так. Я изучаю jQuery и несколько дней был озадачен этой проблемой. Спасибо за четкий, лаконичный ответ. - person Raj; 27.03.2011
comment
.live() устарел в версии 1.7, и его использование не рекомендуется даже в проектах, использующих более старые версии jQuery. - person saluce; 30.07.2012
comment
@saluce - хороший момент, но когда я написал этот ответ, live был очень жив и процветал. - person Anurag; 30.07.2012

Ваш обработчик событий не добавляется к последовательно присоединяемым элементам. Существует несколько способов динамического присоединения обработчика событий. Для более новых версий jQuery (1.7+) используйте функцию .on() с селектором.

$('.container').on('click', 'a.live', function() { alert("I'm on"); });

В старых версиях jQuery нет .on(), поэтому вы можете использовать .live(). Однако одно предостережение заключается в том, что .live() устарело в версии 1.7.

$('a.live').live('click', function() { alert("I'm live"); });

Даже команда jQuery предлагает использовать альтернативы .live(), независимо от используемой версии jQuery. Для версий старше 1.7 используйте .delegate().

$('.container').delegate('a.test', 'click', function() { alert("I'm delegated"); });
person saluce    schedule 26.07.2012

Когда вы подключаете обработчики событий с помощью bind (click – это сокращение для bind("click", ...)), только те элементы, которые уже существуют подключены. Новые, которые вы добавите позже, не будут.

Вы можете использовать live или delegate или функции делегирования on или подключайте их по отдельности при добавлении:

  • Живой пример – использование последней версии jQuery и delegate (вы также можете использовать on, но мне нравится, как delegate документирует мои намерение):

    jQuery(function($) {
    
      $("#theButton").click(function() {
        $("#container").append(
          "<div><a class='test' href='#'>X</a></div>"
        );
      });
    
      $("#container").delegate("a.test", "click", function() {
        alert("Clicked");
      });
    
    });
    
  • Живой пример — использование последней версии jQuery и on (обратите внимание, что порядок аргументов отличается от delegate):

    jQuery(function($) {
    
      $("#theButton").click(function() {
        $("#container").append(
          "<div><a class='test' href='#'>X</a></div>"
        );
      });
    
      $("#container").on("click", "a.test", function() {
        alert("Clicked");
      });
    
    });
    
  • Живой пример – использование вашей версии jQuery (1.3.0?!) и подключение их по мере добавления:

    jQuery(function($) {
    
      $("#theButton").click(function() {
        $("<div><a class='test' href='#'>X</a></div>")
          .click(aTestClick)
          .appendTo("#container");
      });
    
      $("a.test").click(aTestClick);
    
      function aTestClick() {
        alert("Clicked");
      }
    
    });
    

Не по теме (немного):

  1. jQuery 1.3.0 — это девять выпусков, которые устарели более чем на два года. Текущая версия (на момент исходного ответа, март 2011 г.) — 1.5.1, и даже если вы хотите придерживаться дерева 1.3, после 1.3.0 был не один, а два отладочных выпуска.
  2. Вы используете два отдельных вызова ready, сначала явный, а затем неявный (ваш $, где вы передаете функцию). Нужен только один.
  3. Настоятельно рекомендуем не полагаться на вставку точки с запятой, это дьявольское отродье. Заканчивайте свои операторы точкой с запятой, чтобы гарантировать, что скрипты могут быть минимизированы/сжаты/упакованы, и просто потому, что интерпретатор иногда может ошибиться.
person T.J. Crowder    schedule 27.03.2011
comment
Спасибо за примеры. На самом деле я использую последнюю версию jQuery в своем коде, но я нашел в Интернете что-то, что, по-видимому, было немного старым, что использовало текущую версию, и это то, на чем я основывал свой минимальный пример. Спасибо, что упомянули также два готовых вызова --- я только начинаю осваивать jQuery и ценю указатель. Я пришел из Python, где семантически значимые пробелы являются нормой --- нужно привыкнуть заканчивать операторы точкой с запятой. Спасибо еще раз! - person Raj; 27.03.2011
comment
@Raj: Не беспокойтесь, надеюсь, это помогло! Лучший, - person T.J. Crowder; 27.03.2011
comment
.live() устарел, это 1.7, и рекомендуется использовать .on() для 1.7 и выше, или .delegate() до 1.7. - person saluce; 30.07.2012
comment
@ T.J.Crowder Это была ошибка, я не заметил отметки времени, пока не стало слишком поздно, чтобы отменить голосование =/ - person saluce; 30.07.2012