Pytanie Powiązanie zdarzenia na dynamicznie tworzonych elementach?


Mam trochę kodu, w którym przechodzę przez wszystkie pola wyboru na stronie i wiążę .hover wydarzenie dla nich, aby zrobić trochę twiddling z ich szerokości na mouse on/off.

Tak dzieje się na stronie i działa dobrze.

Problem polega na tym, że wszelkie wybrane pola, które dodaję przez Ajax lub DOM po początkowej pętli, nie będą wiązały zdarzenia.

Znalazłem tę wtyczkę (jQuery Live Query Plugin), ale zanim dodaję kolejne 5k do moich stron za pomocą wtyczki, chcę sprawdzić, czy ktoś wie, jak to zrobić, bezpośrednio z jQuery lub inną opcją.


1679
2017-10-14 23:25


pochodzenie


Oto szczegółowy artykuł na temat wiązania zdarzenia kliknięcia dla elementu dynamicznego goo.gl/zlEbnv - Satinder singh


Odpowiedzi:


Od wersji jQuery 1.7 powinieneś użyć jQuery.fn.on:

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

Przed tym, zalecanym podejściem było użycie live():

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

Jednak, live() został wycofany w 1.7 na rzecz on()i całkowicie usunięte w wersji 1.9. The live() podpis:

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

... można zastąpić następującymi on() podpis:

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

Na przykład, jeśli strona dynamicznie tworzyła elementy z nazwą klasy dosomething powiążesz wydarzenie z rodzic, który już istnieje (jest to główny problem tutaj, potrzebujesz czegoś, co istnieje do połączenia, nie wiąż do dynamicznej zawartości), może to być (i najłatwiejsza opcja) document. Chociaż pamiętaj document może nie być najskuteczniejszą opcją.

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

Każdy rodzic, który istnieje w momencie związania zdarzenia, jest w porządku. Na przykład

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

dotyczyłoby

<div class="buttons">
    <!-- <button>s that are generated dynamically and added here -->
</div>

1791
2017-08-09 09:51



Zauważ, że metoda na żywo działa tylko dla określonych zdarzeń, a nie dla innych, takich jak loadmetadata. (Zobacz sekcję zastrzeżeń w dokumentacji.) - Sam Dutton
Dowiedz się więcej o delegowaniu wydarzeń tutaj: learn.jquery.com/events/event-delegation. - Felix Kling
W jaki sposób można to osiągnąć za pomocą czystego javascript / vanilla js? - Ram Patra
@Ramswaroop wszystko, co można zrobić w jQuery można osiągnąć bez jQuery. Oto dobry przykład delegowania wydarzeń bez jQuery - dave
@dave Zastanawiam się, dlaczego odpowiedź, którą wskazałeś, nie jest tutaj wymieniona. Eli najwyraźniej poprosił o rozwiązanie bez żadnej wtyczki, jeśli to możliwe. - Ram Patra


Jest dobre wytłumaczenie w dokumentacji jQuery.fn.on.

W skrócie:

Funkcje obsługi zdarzeń są powiązane tylko z aktualnie wybranymi elementami; muszą istnieć na stronie w momencie, gdy twój kod wywołuje .on().

Tak więc w poniższym przykładzie #dataTable tbody tr musi istnieć przed wygenerowaniem kodu.

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

Jeśli do strony wstrzykiwany jest nowy kod HTML, lepiej jest użyć zdarzeń delegowanych do dołączenia procedury obsługi zdarzeń, tak jak to opisano poniżej.

Zdarzenia delegowane mają tę zaletę, że mogą przetwarzać zdarzenia z elementów potomnych, które są dodawane do dokumentu w późniejszym czasie. Na przykład, jeśli tabela istnieje, ale wiersze są dodawane dynamicznie za pomocą kodu, obsługiwane będzie następujące polecenie:

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

Oprócz zdolności do obsługi zdarzeń na elementach potomnych, które nie zostały jeszcze utworzone, kolejną zaletą delegowanych zdarzeń jest ich możliwość znacznie niższego obciążenia, gdy wiele elementów musi być monitorowanych. Na tabeli danych z 1000 wierszy w jego tbodypierwszy przykład kodu dołącza program do 1000 elementów.

Metoda delegowanych zdarzeń (drugi przykład kodu) dołącza moduł obsługi zdarzeń do tylko jednego elementu: tbody, a wydarzenie wymaga jedynie podniesienia poziomu o jeden poziom (od kliknięcia tr do tbody).

Uwaga: Zdarzenia delegowane nie działają SVG.


301
2017-12-09 07:59



byłoby to lepiej zaakceptowaną odpowiedzią, ponieważ szybciej byłoby delegować z konkretnej tabeli niż z dokumentu (obszar wyszukiwania byłby znacznie mniejszy) - msanjay
@msanjay: Chociaż celowanie w wyszukiwanie bliżej elementów jest preferowane, różnica wyszukiwania / prędkości jest w praktyce bardzo niewielka. Musiałbyś kliknąć 50 000 razy na sekundę, by zauważyć cokolwiek :) - Gone Coding
Czy to podejście może być zastosowane do obsługi kliknięć checkbox z rzędu przez zmianę tr do odpowiedniego selektora, takiego jak 'input[type=checkbox]', a to będzie automatycznie obsługiwane dla nowo wstawionych rzędów? - JoeBrockhaus


To jest czysty JavaScript rozwiązanie bez żadnych bibliotek ani wtyczek:

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

gdzie hasClass jest

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

Wersja demonstracyjna na żywo

Kredyt trafia do Dave'a i Sime Vidasa

Korzystanie z bardziej nowoczesnego JS, hasClass można zaimplementować jako:

function hasClass(elem, className) {
    return elem.classList.contains(className);
}

158
2017-10-14 23:31



stackoverflow.com/questions/9106329/... - zloctb
Możesz użyć Element.classList zamiast dzielić - Eugen Konkov
@EugenKonkov Element.classList nie jest obsługiwany w starszych przeglądarkach. Na przykład IE <9. - Ram Patra
Ładny artykuł o tym, jak zrobić rzeczy przy użyciu skryptu waniliowego zamiast jQuery - toddmotto.com/... - Ram Patra
co powiesz na bulgotanie? Co się stanie, jeśli zdarzenie kliknięcia stanie się dzieckiem elementu, który Cię interesuje? - Andreas Trantidis


Możesz dodawać zdarzenia do obiektów podczas ich tworzenia. Jeśli dodajesz te same zdarzenia do wielu obiektów w różnych momentach, tworzenie nazwanej funkcji może być najlepszym sposobem.

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





Możesz po prostu zawinąć wywołanie zdarzenia zdarzeń w funkcję, a następnie wywołać je dwukrotnie: raz na gotowym dokumencie i raz po zdarzeniu, które dodaje nowe elementy DOM. Jeśli to zrobisz, powinieneś unikać podwójnego wiązania tego samego zdarzenia z istniejącymi elementami, więc będziesz potrzebował albo usunąć istniejące zdarzenia, albo (lepiej) związać tylko z nowymi elementami DOM. Kod będzie wyglądał mniej więcej tak:

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

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

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

40
2018-03-21 22:35



Ten post naprawdę pomógł mi zrozumieć problem, który miałem, ładując ten sam formularz i otrzymując 1,2,4,8,16 ... zgłoszeń. Zamiast używać .live () właśnie użyłem .bind () w moim wywołaniu zwrotnym .load (). Problem rozwiązany. Dzięki! - Thomas McCabe


Spróbuj użyć .live() zamiast .bind(); .live() zwiąże .hover do twojego pola wyboru po wykonaniu żądania Ajax.


37
2017-12-21 07:26



Metoda live() został przestarzały w wersji 1.7 na rzecz on i usunięte w wersji 1.9. - chridam


Możesz użyć metody live () do wiązania elementów (nawet nowo utworzonych) z wydarzeniami i procedurami obsługi, takimi jak zdarzenie onclick.

Oto przykładowy kod, który napisałem, gdzie możesz zobaczyć, w jaki sposób metoda live () wiąże wybrane elementy, nawet nowo utworzone, z wydarzeniami:

<!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



wersja na żywo jest przestarzała - gorgi93


Powiązanie zdarzenia na dynamicznie tworzonych elementach

Pojedynczy element:

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

Element dziecka:

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

Zwróć uwagę na dodane *. Zdarzenie zostanie wywołane dla wszystkich dzieci tego elementu.

Zauważyłem to:

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

Nie działa, ale działało wcześniej. Używam jQuery od Google CDN, ale nie wiem, czy to zmienili.


18
2017-10-07 17:43



Yeap i oni nie mówią (document.body), że mówi przodek, który może być prawie wszystkim - MadeInDreams


Innym rozwiązaniem jest dodanie detektora podczas tworzenia elementu. Zamiast umieszczać słuchacza w ciele, umieszczasz słuchacza w elemencie w momencie jego utworzenia:

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



Twój kod zawiera 1 błąd: myElement.append('body'); musi być myElement.appendTo('body');. Z drugiej strony, jeśli nie ma potrzeby dalszego korzystania z zmiennej myElement w ten sposób jest łatwiej i krócej: $('body').append($('<button/>', { text: 'Go to Google!' }).bind( 'click', goToGoogle)); - ddlab