Привязка событий к динамически создаваемым элементам?

1678

У меня есть немного кода, где я просматриваю все поля выбора на странице и привязываю к нему событие .hover, чтобы сделать немного спрятаться с их шириной на mouse on/off.

Это происходит на странице готово и прекрасно работает.

Проблема заключается в том, что любые поля выбора, которые я добавляю через Ajax или DOM после начального цикла, не будут иметь привязки к событию.

Я нашел этот плагин (jQuery Live Query Plugin), но прежде чем добавить еще 5 к моим страницам с плагином, я хочу посмотрите, знает ли кто-нибудь способ сделать это, либо с помощью jQuery напрямую, либо с помощью другого параметра.

  • 11
    Вот подробная статья о том, как связать событие клика для динамического элемента goo.gl/zlEbnv
Теги:
events
unobtrusive-javascript

24 ответа

1833
Лучший ответ

Начиная с jQuery 1.7 вы должны использовать jQuery.fn.on:

$(staticAncestors).on(eventName, dynamicChild, function() {});

До этого рекомендуется использовать live():

$(selector).live( eventName, function(){} );

Однако live() устарел в 1.7 в пользу on() и полностью удален в 1.9. Подпись live():

$(selector).live( eventName, function(){} );

... можно заменить на следующую: on() подпись:

$(document).on( eventName, selector, function(){} );

Например, если ваша страница динамически создавала элементы с именем класса dosomething вы привязывали бы событие к родительскому, который уже существует (это суть проблемы здесь, вам нужно что-то, что существует для привязки, не привязывать к динамический контент), это может быть (и самый простой вариант) - это document. Хотя иметь в виду document возможно, не самый эффективный вариант.

$(document).on('mouseover mouseout', '.dosomething', function(){
    // what you want to happen when mouseover and mouseout 
    // occurs on elements that match '.dosomething'
});

Любой родитель, который существует в момент привязки события, прекрасен. Например

$('.buttons').on('click', 'button', function(){
    // do something here
});

будет применяться к

<div class="buttons">
    <!-- <button>s that are generated dynamically and added here -->
</div>
  • 6
    Обратите внимание, что метод live работает только для определенных событий, а не для других, таких как загруженные метаданные. (См. Раздел предостережений в документации.)
  • 42
    Узнайте больше о делегировании событий здесь: learn.jquery.com/events/event-delegation .
Показать ещё 10 комментариев
323

В документации jQuery.fn.on.

Короче:

Обработчики событий привязаны только к выбранным в данный момент элементам; они должны существовать на странице в момент, когда ваш код делает вызов .on().

Таким образом, в следующем примере #dataTable tbody tr должен существовать до генерации кода.

$("#dataTable tbody tr").on("click", function(event){
    console.log($(this).text());
});

Если на страницу вводится новый HTML-код, предпочтительнее использовать делегированные события для присоединения обработчика событий, как описано ниже.

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

$("#dataTable tbody").on("click", "tr", function(event){
    console.log($(this).text());
});

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

Подход с делегированными событиями (второй пример кода) присоединяет обработчик события только к одному элементу tbody, и событию нужно только пузырьки на один уровень (от нажатого tr до tbody).

Примечание. Делегированные события не работают для SVG.

  • 11
    это был бы более приемлемый ответ, потому что было бы быстрее делегировать из определенной таблицы, а не полностью из документа (область поиска была бы намного меньше)
  • 5
    @msanjay: хотя нацеливание поиска ближе к элементам является предпочтительным, на практике разница между поиском и скоростью очень мала. Вам придется нажимать 50000 раз в секунду, чтобы заметить что-нибудь :)
Показать ещё 1 комментарий
174

Это чистое решение JavaScript без каких-либо библиотек или плагинов:

document.addEventListener('click', function (e) {
    if (hasClass(e.target, 'bu')) {
        // .bu clicked
        // Do your thing
    } else if (hasClass(e.target, 'test')) {
        // .test clicked
        // Do your other thing
    }
}, false);

где hasClass

function hasClass(elem, className) {
    return elem.className.split(' ').indexOf(className) > -1;
}

Live demo

Кредит принадлежит Дейву и Симе Видасу

Используя более современную JS, hasClass можно реализовать как:

function hasClass(elem, className) {
    return elem.classList.contains(className);
}
  • 4
    stackoverflow.com/questions/9106329/...
  • 6
    Вы можете использовать Element.classList вместо разделения
Показать ещё 4 комментария
58

Вы можете добавлять события к объектам при их создании. Если вы добавляете одни и те же события к нескольким объектам в разное время, создание именованной функции может быть способом.

var mouseOverHandler = function() {
    // Do stuff
};
var mouseOutHandler = function () {
    // Do stuff
};

$(function() {
    // On the document load, apply to existing elements
    $('select').hover(mouseOverHandler, mouseOutHandler);
});

// This next part would be in the callback from your Ajax call
$("<select></select>")
    .append( /* Your <option>s */ )
    .hover(mouseOverHandler, mouseOutHandler)
    .appendTo( /* Wherever you need the select box */ )
;
44

Вы можете просто связать вызов привязки события к функции, а затем вызвать его дважды: один раз на документе готов и один раз после вашего события, которое добавляет новые элементы DOM. Если вы это сделаете, вы захотите избежать связывания одного и того же события дважды с существующими элементами, поэтому вам нужно либо отменить существующие события, либо (лучше) привязать только к вновь созданным элементам DOM. Код будет выглядеть примерно так:

function addCallbacks(eles){
    eles.hover(function(){alert("gotcha!")});
}

$(document).ready(function(){
    addCallbacks($(".myEles"))
});

// ... add elements ...
addCallbacks($(".myNewElements"))
  • 2
    Этот пост действительно помог мне понять проблему, с которой я загружал ту же форму и получал 1,2,4,8,16 ... заявок. Вместо использования .live () я просто использовал .bind () в моем обратном вызове .load (). Задача решена. Спасибо!
38

Попробуйте использовать .live() вместо .bind(); .live() привяжет .hover к вашему флажку после выполнения запроса Ajax.

  • 31
    Метод live() устарел в версии 1.7 в пользу on и удален в версии 1.9.
20

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

Вот пример кода, который я написал, где вы можете увидеть, как метод live() связывает выбранные элементы, даже вновь созданные, с событиями:

<!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>Untitled Document</title>
    </head>

    <body>
        <script src="http://code.jquery.com/jquery-latest.js"></script>
        <script src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.16/jquery-ui.min.js"></script>

        <input type="button" id="theButton" value="Click" />
        <script type="text/javascript">
            $(document).ready(function()
                {
                    $('.FOO').live("click", function (){alert("It Works!")});
                    var $dialog = $('<div></div>').html('<div id="container"><input type ="button" id="CUSTOM" value="click"/>This dialog will show every time!</div>').dialog({
                                                                                                         autoOpen: false,
                                                                                                         tite: 'Basic Dialog'
                                                                                                     });
                    $('#theButton').click(function()
                    {
                        $dialog.dialog('open');
                        return('false');
                    });
                    $('#CUSTOM').click(function(){
                        //$('#container').append('<input type="button" value="clickmee" class="FOO" /></br>');
                        var button = document.createElement("input");
                        button.setAttribute('class','FOO');
                        button.setAttribute('type','button');
                        button.setAttribute('value','CLICKMEE');
                        $('#container').append(button);
                    });
                    /* $('#FOO').click(function(){
                                                     alert("It Works!");
                                                 }); */
            });
        </script>
    </body>
</html>
  • 3
    жить не рекомендуется
18

Связывание событий с динамически создаваемыми элементами

Одиночный элемент:

$(document.body).on('click','.element', function(e) {  });

Детский элемент:

 $(document.body).on('click','.element *', function(e) {  });

Обратите внимание на добавленный *. Событие будет инициировано для всех дочерних элементов этого элемента.

Я заметил, что:

$(document.body).on('click','.#element_id > element', function(e) {  });

Он больше не работает, но он работал раньше. Я использую jQuery из Google CDN, но я не знаю, изменили ли они его.

  • 0
    Да, и они не говорят (document.body), что это говорит о предке, который может быть чем угодно
16

Я предпочитаю использовать селектор, и я применяю его в документе.

Это привязывается к документу и будет применяться к элементам, которые будут отображаться после загрузки страницы.

Например:

$(document).on("click", $(selector), function() {
    // Your code here
});
  • 2
    селектор не должен быть заключен в $, поэтому правильный формат будет $ (document) .on («click», «selector», function () {// Ваш код здесь});
  • 1
    Также бессмысленно оборачивать объект jQuery вокруг переменной selector , когда он должен содержать либо строку, либо объект Element, который вы можете просто передать непосредственно этому аргументу on()
16

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

var myElement = $('<button/>', {
    text: 'Go to Google!'
});

myElement.bind( 'click', goToGoogle);
myElement.append('body');


function goToGoogle(event){
    window.location.replace("http://www.google.com");
}
  • 0
    Ваш код содержит 1 ошибку: myElement.append('body'); должен быть myElement.appendTo('body'); , С другой стороны, если нет необходимости дальнейшего использования переменной myElement это проще и короче так: $('body').append($('<button/>', { text: 'Go to Google!' }).bind( 'click', goToGoogle));
11

Вы можете присоединить событие к элементу при динамическом создании с помощью jQuery(html, attributes).

Как и jQuery 1.8, любой метод экземпляра jQuery (метод jQuery.fn) может использоваться как свойство объекта, переданного в второй параметр:

function handleDynamicElementEvent(event) {
  console.log(event.type, this.value)
}
// create and attach event to dynamic element
jQuery("<select>", {
    html: $.map(Array(3), function(_, index) {
      return new Option(index, index)
    }),
    on: {
      change: handleDynamicElementEvent
    }
  })
  .appendTo("body");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
11

Обратите внимание на класс "MAIN", который помещается, например,

<div class="container">
     <ul class="select">
         <li> First</li>
         <li>Second</li>
    </ul>
</div>

В приведенном выше сценарии объект MAIN, который будет наблюдать jQuery, является "контейнером".

Тогда у вас будут в основном имена элементов под контейнером, такие как ul, li и select:

$(document).ready(function(e) {
    $('.container').on( 'click',".select", function(e) {
        alert("CLICKED");
    });
 });
10

вы можете использовать

$('.buttons').on('click', 'button', function(){
    // your magic goes here
});

или

$('.buttons').delegate('button', 'click', function() {
    // your magic goes here
});

эти два метода эквивалентны, но имеют другой порядок параметров.

см. событие делегирования jQuery

  • 1
    delegate() теперь устарел. Не используйте это.
7

Вот почему динамически созданные элементы не реагируют на клики  :

var body = $("body");
var btns = $("button");
var btnB = $("<button>B</button>");
// `<button>B</button>` is not yet in the document.
// Thus, `$("button")` gives `[<button>A</button>]`.
// Only `<button>A</button>` gets a click listener.
btns.on("click", function () {
  console.log(this);
});
// Too late for `<button>B</button>`...
body.append(btnB);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>A</button>

В качестве обходного пути вы должны прослушать все клики и проверить исходный элемент  :

var body = $("body");
var btnB = $("<button>B</button>");
var btnC = $("<button>C</button>");
// Listen to all clicks and
// check if the source element
// is a `<button></button>`.
body.on("click", function (ev) {
  if ($(ev.target).is("button")) {
    console.log(ev.target);
  }
});
// Now you can add any number
// of `<button></button>`.
body.append(btnB);
body.append(btnC);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>A</button>

Это называется "Event Delegation". Хорошие новости, это встроенная функция в jQuery: -)

var i = 11;
var body = $("body");
body.on("click", "button", function () {
  var letter = (i++).toString(36).toUpperCase();
  body.append($("<button>" + letter + "</button>"));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>A</button>
7

Любой p arent, который существует в момент привязки события, и если ваша страница динамически создавала элементы с именем класса , вы свяжет событие с родителем, который уже существует

$(document).ready(function(){
  //Particular Parent chield click
  $(".buttons").on("click","button",function(){
    alert("Clicked");
  });  
  
  //Dynamic event bind on button class  
  $(document).on("click",".button",function(){
    alert("Dymamic Clicked");
  });
  $("input").addClass("button");  
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="buttons">
  <input type="button" value="1">
  <button>2</button>
  <input type="text">
  <button>3</button>  
  <input type="button" value="5">  
  </div>
<button>6</button>
6

Попробуйте это -

$(document).on( 'click', '.click-activity', function () { ... });
3

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

$('.wrapper-class').on("click", '.selector-class', function() {
    // Your code here
});

Замечания:

Элемент класса-обертки может быть чем угодно. документ, тело или ваша обертка. Оболочка уже должна существовать.

3

var myElement = $('<button/>', {
    text: 'Go to Google!'
});

myElement.bind( 'click', goToGoogle);
myElement.append('body');


function goToGoogle(event){
  window.location.replace("http://www.google.com");
}
3

Используйте метод .on() для jQuery http://api.jquery.com/on/ для присоединения обработчиков событий к элементу live.

Также удаляется метод версии 1.9 .live().

2

Свяжите событие с родителем, который уже существует:

$(document).on("click", "selector", function() {
    // Your code here
});
1

Я предпочитаю, чтобы прослушиватели событий были развернуты модульной функцией, а не сценарием слушателя событий уровня document. Итак, мне нравится ниже. Обратите внимание: вы не можете переадресовать элемент с одним и тем же прослушивателем событий, поэтому не беспокойтесь о том, чтобы добавить слушателя более одного раза - только один палец.

var iterations = 4;
var button;
var body = document.querySelector("body");

for (var i = 0; i < iterations; i++) {
    button = document.createElement("button");
    button.classList.add("my-button");
    button.appendChild(document.createTextNode(i));
    button.addEventListener("click", myButtonWasClicked);
    body.appendChild(button);
}

function myButtonWasClicked(e) {
    console.log(e.target); //access to this specific button
}
  • 0
    Я предпочитаю эту реализацию; Я просто должен перезвонить
1

Более гибкое решение для создания элементов и привязки событий (источник)

// creating a dynamic element (container div)
var $div = $("<div>", {id: 'myid1', class: 'myclass'});

//creating a dynamic button
 var $btn = $("<button>", { type: 'button', text: 'Click me', class: 'btn' });

// binding the event
 $btn.click(function () { //for mouseover--> $btn.on('mouseover', function () {
    console.log('clicked');
 });

// append dynamic button to the dynamic container
$div.append($btn);

// add the dynamically created element(s) to a static element
$("#box").append($div);

Примечание. Это создаст экземпляр обработчика события для каждого элемента (может повлиять на производительность при использовании в цикле)

-1

Я искал решение, чтобы получить $.bind и $.unbind без проблем работать в динамически добавленных элементах.

Поскольку on() делает трюк для присоединения событий, чтобы создать фальшивый отрыв от тех, к которым я пришел:

const sendAction = function(e){ ... }
// bind the click
$('body').on('click', 'button.send', sendAction );

// unbind the click
$('body').on('click', 'button.send', function(){} );
  • 0
    Расцепление не работает, это просто добавляет другое событие, которое указывает на пустую функцию ...
  • 1
    Чтобы отменить привязку события, используйте off ()
-2
<html>
    <head>
        <title>HTML Document</title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
    </head>

    <body>
        <div id="hover-id">
            Hello World
        </div>

        <script>
            jQuery(document).ready(function($){
                $(document).on('mouseover', '#hover-id', function(){
                    $(this).css('color','yellowgreen');
                });

                $(document).on('mouseout', '#hover-id', function(){
                    $(this).css('color','black');
                });
            });
        </script>
    </body>
</html>
  • 2
    Хотя этот фрагмент кода может решить проблему, он не объясняет, почему и как он отвечает на вопрос. Пожалуйста, включите объяснение вашего кода, так как это действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин, по которым вы предлагаете код.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню