Питання Прив'язка події до динамічно створених елементів?


Я маю трохи коду, куди я проходжу через всі поля вибору на сторінці та прив'язуючи a .hover подія, щоб вони зробили трохи шипшини з їх шириною mouse on/off.

Це відбувається на сторінці готово і працює просто добре.

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

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


1679
2017-10-14 23:25


походження


Нижче наведено докладну статтю про те, як прив'язувати подію для кліку для динамічного елемента goo.gl/zlEbnv - Satinder singh


Відповіді:


З jQuery 1.7 ви повинні використовувати jQuery.fn.on:

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

До цього, рекомендований підхід був використаний live():

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

Однак live() був затриманий в 1.7 на користь on(), і повністю вилучено в 1.9. The 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>

1791
2017-08-09 09:51



Зверніть увагу, що метод live працює лише для певних подій, а не інших, таких як завантажені метадані. (Див. Розділ застережень у документації.) - Sam Dutton
Дізнайтеся більше про делегування подій тут: learn.jquery.com/events/event-delegation. - Felix Kling
Будь-який спосіб це зробити за допомогою чистого JavaScript / vanilla js? - Ram Patra
@Ramswaroop все, що ви можете зробити в jQuery, можна виконати без jQuery. Ось хороший приклад делегування подій без jQuery - dave
@dave Мені цікаво, чому відповідь, яку ви вказали, тут не вказана. Елі чітко попросив про рішення без будь-якого плагіна, якщо це можливо. - Ram Patra


Існує хороше пояснення в документації 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.


301
2017-12-09 07:59



це було б кращою прийнятою відповіддю, оскільки швидше буде делегувати з конкретної таблиці, а не від документа (область пошуку буде набагато меншою) - msanjay
@smangjay: хоча націлювання на пошук ближче до елементів є кращим, різниця між пошуком / швидкістю на практиці дуже незначна. Вам доведеться натиснути 50 000 разів на секунду, щоб помітити щось :) - Gone Coding
Чи можна застосувати цей підхід для переміщення кліків у рядку, змінюючи їх tr до відповідного селектора, наприклад 'input[type=checkbox]', і це буде автоматично оброблено для вставлених рядків? - JoeBrockhaus


Це чистий 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);
}

158
2017-10-14 23:31



stackoverflow.com/questions/9106329/... - zloctb
Ви можете використовувати Element.classList замість розколу - Eugen Konkov
@ Євген Коньков Element.classList не підтримується підтримується старими браузерами. Наприклад, IE <9. - Ram Patra
Хороша стаття про те, як зробити все, використовуючи ванільний сценарій, а не jQuery - toddmotto.com/... - Ram Patra
як про бульки? Що робити, якщо подія кліків відбулася у дитини елемента, який вас цікавить? - Andreas Trantidis


Ви можете додавати події до об'єктів під час їх створення. Якщо ви додаєте ті самі події до кількох об'єктів у різний час, створення іменованої функції може бути способом переходу.

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 */ )
;

59
2017-10-14 23:35





Ви можете просто загорнути прив'язку виклику події до функції, а потім викликати її двічі: один раз у документі готовий і один раз після вашої події, яка додає нові елементи DOM. Якщо ви це зробите, ви хочете, щоб двічі не зв'язати одну і ту ж подію з існуючими елементами, тому вам потрібно буде роз'єднати існуючі події або (краще) лише пов'язувати з новоствореними елементами DOM. Код буде виглядати приблизно так:

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

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

// ... add elements ...
addCallbacks($(".myNewElements"))

40
2018-03-21 22:35



Цей пост дійсно допоміг мені зрозуміти проблему, яку я мав завантаження тієї ж форми і отримати 1,2,4,8,16 ... подання. Замість використання .live () я просто використав .bind () у своєму .load () зворотному дзвінку. Проблема вирішена. Дякую! - Thomas McCabe


Спробуйте використати .live() замість .bind(); в .live() зв'яжеться .hover до вашого прапорця після виконання запиту Ajax.


37
2017-12-21 07:26



Метод live() був затриманий у версії 1.7 на користь on і видалено в версії 1.9. - chridam


Ви можете використовувати метод live () для прив'язки елементів (навіть нових) до подій та обробників, наприклад, onclick event.

Ось приклад коду, який я написав, де ви можете побачити, як метод 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>

21
2018-01-22 01:06



жити не підлягає - gorgi93


Зв'язок події для динамічно створюваних елементів

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

$(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, але я не знаю, чи змінили вони це.


18
2017-10-07 17:43



Yeap та вони не кажуть (document.body) це каже предка, котрий міг бути майже будь що - MadeInDreams


Іншим рішенням є додавання слухача при створенні елемента. Замість того, щоб помістити слухача в тіло, ви кладете слухача в елемент у той момент, коли його створюєте:

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

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


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

16
2017-11-21 12:01



Ваш код містить 1 помилку: myElement.append('body'); повинно бути myElement.appendTo('body');. З іншого боку, якщо немає потреби в подальшому використанні змінної myElement це легше та коротше таким чином: $('body').append($('<button/>', { text: 'Go to Google!' }).bind( 'click', goToGoogle)); - ddlab


Я вважаю за краще використовувати селектор і застосувати його до документа.

Це пов'язує себе з документом і буде застосовуватися до елементів, які будуть відтворюватися після завантаження сторінки.

Наприклад:

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

16
2018-04-05 07:11



селектор не повинен містити $, таким чином правильний формат буде $ (document) .on ("click", "selector", function () {// ваш код тут}); - autopilot
Не варто також обертати об'єкт jQuery навколо selector variable, коли він повинен містити рядок або об'єкт Element, який ви можете просто перейти безпосередньо до цього аргументу on() - Rory McCrossan


Ви можете додавати події до елемента під час динамічного створення 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
2018-03-26 02:15