jQuery, как привязать событие onclick к динамически добавляемому элементу HTML

Я хочу привязать событие onclick к элементу, который я вставляю динамически с помощью jQuery

Но он никогда не запускает связанную функцию. Я был бы счастлив, если бы вы могли указать, почему этот пример не работает и как я могу заставить его работать правильно:

<!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" xml:lang="da" lang="da">
        <head>
          <title>test of click binding</title>

<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
          <script type="text/javascript">


        jQuery(function(){
          close_link = $('<a class="" href="#">Click here to see an alert</a>');
          close_link.bind("click", function(){
            alert('hello from binded function call');
            //do stuff here...
          });
  
          $('.add_to_this').append(close_link);
        });
          </script>
        </head>
        <body>
          <h1 >Test of click binding</h1>
          <p>problem: to bind a click event to an element I append via JQuery.</p>

          <div class="add_to_this">
            <p>The link is created, then added here below:</p>
          </div>

          <div class="add_to_this">
            <p>Another is added here below:</p>
          </div>


        </body>
        </html>

РЕДАКТИРОВАТЬ: я отредактировал пример, чтобы он содержал два элемента, в которые вставлен метод. В этом случае вызов alert() никогда не выполняется. (спасибо @Daff за указание на это в комментарии)


person Jesper Rønn-Jensen    schedule 06.10.2009    source источник
comment
Страница вашего примера работает нормально, когда я тестировал ее в FF 3.5   -  person Daff    schedule 06.10.2009
comment
@Daff К сожалению, ты прав! Затем я, по-видимому, извлек часть своего кода, которая действительно работает. Спасибо что подметил это!   -  person Jesper Rønn-Jensen    schedule 06.10.2009
comment
@Daff, я отредактировал пример, чтобы он содержал два места для вставки метода. Потом он действительно перестал работать :)   -  person Jesper Rønn-Jensen    schedule 06.10.2009


Ответы (7)


Первая проблема заключается в том, что когда вы вызываете append для набора jQuery с более чем одним элементом, для каждого создается клон добавляемого элемента, и, таким образом, присоединенный наблюдатель событий теряется.

Альтернативный способ сделать это - создать ссылку для каждого элемента:

function handler() { alert('hello'); }
$('.add_to_this').append(function() {
  return $('<a>Click here</a>').click(handler);
})

Другая потенциальная проблема может заключаться в том, что наблюдатель событий прикрепляется до того, как элемент был добавлен в DOM. Я не уверен, есть ли здесь что сказать, но я думаю, что такое поведение можно считать неопределенным. Более надежным подходом, вероятно, будет:

function handler() { alert('hello'); }
$('.add_to_this').each(function() {
  var link = $('<a>Click here</a>');
  $(this).append(link);
  link.click(handler);
});
person Tobias    schedule 07.10.2009
comment
возникает проблема, когда вам нужно привязать клики к элементам, к которым добавлены другие функции. Вот почему я предлагаю использовать ответ aM1Ne. - person Edoardoo; 27.05.2014
comment
Действительно, когда вы ориентируетесь на известные структуры разметки, созданные каким-то другим кодом. Но здесь он сам вставлял элементы, и для них нет четкого селектора (это просто привязка, которых может быть много), поэтому ему придется добавить дополнительную разметку, чтобы иметь возможность нацелить элемент. В этом случае так же легко прикрепить обработчик к элементу напрямую, вместо того, чтобы фиксировать все щелчки и проверять соответствие селектора. - person Tobias; 28.05.2014
comment
Я понимаю ваш ответ, это не значит, что он был неправильным. Конечно, иметь возможность динамически вводить некоторый html (например, ul li изображений, загруженных с помощью ajax с бесконечной прокруткой) и уже имея кнопки, привязанные к некоторому действию (например, лайтбокс), это намного удобнее. - person Edoardoo; 29.05.2014
comment
Этот ответ также очень полезен для случаев, когда по умолчанию доступна более старая версия jQuery (например, Drupal 7). on() был представлен в jQuery 1.7. - person Wtower; 24.06.2014

Все эти методы устарели. Вы должны использовать метод on для решения вашей проблемы.

Если вы хотите настроить таргетинг на динамически добавляемый элемент, вам придется использовать

$(document).on('click', selector-to-your-element , function() {
     //code here ....
});

это заменяет устаревший метод .live().

person aM1Ne    schedule 01.10.2012
comment
*selector-to-your-element* должно быть '.some-class' или '#some-id' - person Alan Shortis; 14.06.2013
comment
Моя проблема заключалась в том, что я делал что-то вроде $('.row').on('click', function(){...}); вместо $(document).on('click','.row',function(){...}); - person Vishnoo Rath; 04.07.2013
comment
Помните, что $(document) может быть любым элементом, который не изменяется на вашей странице. Это предотвращает чрезмерное всплытие событий, ускоряя ваш JS. Например. $(document) - ›$('.example-container') - person Ricky Boyce; 18.11.2013
comment
Подробное объяснение - stackoverflow.com/questions/203198 / - person Alexei Levenkov; 17.08.2016

Как насчет метода Live?

$('.add_to_this a').live('click', function() {
    alert('hello from binded function call');
});

Тем не менее, то, что вы сделали, похоже, должно сработать. Есть другой пост, который выглядит очень похожим.

person Brother Erryn    schedule 06.10.2009
comment
Вы правы, что это действительно сработало. моя ошибка. Итак, я отредактировал вопрос. - person Jesper Rønn-Jensen; 06.10.2009
comment
Да, именно для решения таких задач и предназначены прямые трансляции. - person Powerlord; 06.10.2009
comment
Проблема не связана с живыми событиями, хотя в этом случае прямая трансляция решит ее. Ответ, предоставленный Даффом, также решает проблему, и делает это без добавления новой концепции живых событий в уравнение. - person Jesper Rønn-Jensen; 06.10.2009
comment
Могу также добавить, что в настоящее время это де-факто способ привязки событий. Итак, сегодня я бы также использовал live() в пользу bind(). - person Jesper Rønn-Jensen; 24.06.2011
comment
live() теперь устарел и заменен on() ссылкой - person TrophyGeek; 10.01.2012
comment
live() устарел и заменен на _ 2_ в jQuery 1.9 - person Walter Roman; 15.11.2014

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

Тем не менее, переключить live на on непросто, потому что синтаксис немного отличается:

Новый метод (пример 1):

$(document).on('click', '#someting', function(){

});

Устаревший метод (пример 2):

$('#something').live(function(){

});

Как показано выше, разница есть. Поворот в том, что .on() на самом деле может быть вызван аналогично .live(), передав селектор самой функции jQuery:

Пример 3:

$('#something').on('click', function(){

});

Однако без использования $(document), как в примере 1, пример 3 не будет работать для динамически создаваемых элементов. Пример 3 абсолютно хорош, если вам не нужно динамическое делегирование.

Следует ли использовать $ (document) .on () для всего?

Это будет работать, но если вам не нужно динамическое делегирование, было бы более подходящим использовать пример 3, потому что пример 1 требует немного больше работы от браузера. Это не окажет реального влияния на производительность, но имеет смысл использовать наиболее подходящий для вас метод.

Следует ли использовать .on () вместо .click (), если динамическое делегирование не требуется?

Не обязательно. Ниже приведен всего лишь ярлык, например 3:

$('#something').click(function(){

});

Вышеупомянутое совершенно верно, поэтому выбор метода зависит от личных предпочтений, если динамическое делегирование не требуется.

Использованная литература:

person MrCode    schedule 13.06.2013

Учти это:

jQuery(function(){
  var close_link = $('<a class="" href="#">Click here to see an alert</a>');
      $('.add_to_this').append(close_link);
      $('.add_to_this').children().each(function()
      {
        $(this).click(function() {
            alert('hello from binded function call');
            //do stuff here...
        });
      });
});

Он будет работать, потому что вы прикрепите его к каждому конкретному элементу. Вот почему вам нужно - после добавления ссылки в DOM - найти способ явно выбрать добавленный элемент в качестве элемента JQuery в DOM и привязать к нему событие щелчка.

Лучшим способом, вероятно, будет - как предлагается - привязать его к определенному классу с помощью метода live.

person Daff    schedule 06.10.2009
comment
Спасибо за ответ, Дафф. Не может быть правды, что я могу добавлять прослушиватели событий только к элементам в DOM. Однако сейчас я изменю свой код для этого. (не должно быть проблем, поскольку я просто добавляю специальный класс css для добавленных ссылок). - person Jesper Rønn-Jensen; 06.10.2009
comment
Да, вы правы, это не DOM (он действительно работает с одним), извините. Но я также обнаружил, что привязка к динамически создаваемым элементам кажется довольно раздражающей, если они не могут быть выбраны отдельным селектором jQuery. - person Daff; 06.10.2009
comment
привет от вызова функции BOUND. Извините, в этом посте их слишком много (вся страница; вопросы и ответы), и я просто хочу помочь, вы знаете, прояснить это. - person Scott Fraley; 12.12.2016

Возможно, а иногда и необходимо создать событие щелчка вместе с элементом. Это, например, когда привязка на основе селектора не является вариантом. Главное - избежать проблемы, о которой говорил Тобиас, используя .replaceWith() в одном элементе. Обратите внимание, что это всего лишь доказательство концепции.

<script>
    // This simulates the object to handle
    var staticObj = [
        { ID: '1', Name: 'Foo' },
        { ID: '2', Name: 'Foo' },
        { ID: '3', Name: 'Foo' }
    ];
    staticObj[1].children = [
        { ID: 'a', Name: 'Bar' },
        { ID: 'b', Name: 'Bar' },
        { ID: 'c', Name: 'Bar' }
    ];
    staticObj[1].children[1].children = [
        { ID: 'x', Name: 'Baz' },
        { ID: 'y', Name: 'Baz' }
    ];

    // This is the object-to-html-element function handler with recursion
    var handleItem = function( item ) {
        var ul, li = $("<li>" + item.ID + " " + item.Name + "</li>");

        if(typeof item.children !== 'undefined') {
            ul = $("<ul />");
            for (var i = 0; i < item.children.length; i++) {
                ul.append(handleItem(item.children[i]));
            }
            li.append(ul);
        }

        // This click handler actually does work
        li.click(function(e) {
            alert(item.Name);
            e.stopPropagation();
        });
        return li;
    };

    // Wait for the dom instead of an ajax call or whatever
    $(function() {
        var ul = $("<ul />");

        for (var i = 0; i < staticObj.length; i++) {
            ul.append(handleItem(staticObj[i]));
        }

        // Here; this works.
        $('#something').replaceWith(ul);
    });
</script>
<div id="something">Magical ponies ♥</div>
person Joel Peltonen    schedule 09.07.2013

Я считаю, что это хороший способ:

$('#id').append('<a id="#subid" href="#">...</a>');
$('#subid').click( close_link );
person yogsototh    schedule 06.10.2009
comment
Я не могу использовать #id для добавления к элементу, потому что хочу сделать это для многих элементов. Смотрите обновленный пример кода :) - person Jesper Rønn-Jensen; 06.10.2009