Dinamik olarak oluşturulan öğeler üzerinde olay bağlama?


1677

Bir sayfadaki tüm seçim kutuları arasında döngü .hoverve genişliklerini ile twiddling biraz yapmak için onlara bir olay bağlama kod biraz var mouse on/off.

Bu sayfada hazır olur ve iyi çalışır.

Sahip olduğum sorun, ilk döngüden sonra Ajax veya DOM ile eklediğim herhangi bir seçim kutusunun olay bağlı olmayacak olmasıdır.

Bu eklentiyi ( jQuery Live Query Eklentisi ) buldum , ancak bir eklenti ile sayfalarıma başka bir 5k eklemeden önce, birinin bunu yapmanın bir yolunu bilip bilmediğini görmek istiyorum, doğrudan jQuery ile veya başka bir seçenekle.

Yanıtlar:


2250

JQuery 1.7'den itibaren şunları kullanmalısınız jQuery.fn.on:

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

Bundan önce , önerilen yaklaşım aşağıdakileri kullanmaktı live():

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

Bununla birlikte, live()1.7 lehine on()kaldırılmış ve 1.9'da tamamen kaldırılmıştır. live()imza:

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

... aşağıdaki on()imzayla değiştirilebilir :

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

Örneğin, sayfanız dinamik olarak sınıf adıyla öğeler oluşturuyorsa dosomething, etkinliği zaten var olan bir üst öğeye bağlarsınız (buradaki sorunun özüdür, bağlanmak için var olan bir şeye ihtiyacınız vardır, dinamik içerik), bu olabilir (ve en kolay seçenek) document. Ancak akılda documenttutulması en etkili seçenek olmayabilir .

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

Olayın bağlı olduğu sırada varolan herhangi bir üst öğe iyidir. Örneğin

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

için geçerli olurdu

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

7
Canlı yöntemin yalnızca belirli etkinlikler için çalıştığını ve yüklenen veri verileri gibi diğer etkinliklerde çalışmadığını unutmayın. (Belgelerdeki uyarılar bölümüne bakın.)
Sam Dutton

48
Etkinlik yetkilendirmesi hakkında daha fazla bilgiyi burada bulabilirsiniz: learn.jquery.com/events/event-delegation .
Felix Kling

9
Bunu saf javascript / vanilla js ile başarmanın herhangi bir yolu var mı?
Ram Patra

15
@ Jsuery içinde yapabileceğiniz her şey jQuery olmadan yapılabilir. İşte jQuery olmadan olay delegasyonu için iyi bir örnek
Dave

5
@dave Belirttiğiniz cevabın neden burada yer almadığını merak ediyorum. Eli mümkünse eklentisi olmayan bir çözüm istedi.
Ram Patra

377

Belgelerinde iyi bir açıklama var jQuery.fn.on.

Kısacası:

Olay işleyicileri yalnızca seçili öğelere bağlıdır; kodunuzun çağrıldığı sırada sayfada bulunmaları gerekir .on().

Bu nedenle #dataTable tbody tr, kod oluşturulmadan önce aşağıdaki örnekte bulunmalıdır.

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

Sayfaya yeni HTML enjekte ediliyorsa, bir sonraki bölümde açıklandığı gibi bir olay işleyici eklemek için yetki verilen olayların kullanılması tercih edilir.

Yetki verilen olayların avantajı, daha sonra belgeye eklenen alt öğelerin olaylarını işleyebilmesidir. Örneğin, tablo varsa, ancak satırlar kod kullanılarak dinamik olarak eklenirse, aşağıdakiler tabloyu işleyecektir:

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

Henüz yaratılmayan torun öğeleri üzerindeki olayları işleme yeteneklerine ek olarak, devredilen olayların bir başka avantajı, birçok öğenin izlenmesi gerektiğinde çok daha düşük ek yük potansiyeli olmasıdır. 1.000 satır içeren bir veri tablosunda tbody, ilk kod örneği 1.000 öğeye bir işleyici ekler.

Yetki olayları yaklaşım (ikinci kod örneği) tek bir eleman, bir olay işleyicisi bağlanır tbodyve etkinlik yalnızca (tıklandığında bir seviye kadar kabarcık ihtiyacı triçin tbody).

Not: Yetki verilen etkinlikler SVG için çalışmaz .


11
bu daha iyi kabul edilen bir yanıt olacaktır çünkü belgeden tüm yol yerine (belirli bir alandan temsilci seçmek daha hızlı olacaktır) (arama alanı çok daha küçük olacaktır)
msanjay

5
@ msanjay: Aramayı öğelere daha yakın hedeflemek tercih edilmesine rağmen, arama / hız farkı pratikte çok küçüktür. Bir şey fark etmek için saniyede 50.000 kez tıklamanız gerekir :)
Gone Coding

2
Bu yaklaşım tr, uygun bir seçiciye geçerek üst üste onay kutusu tıklamalarını işlemek için uygulanabilir mi 'input[type=checkbox]'ve bu, yeni eklenen satırlar için otomatik olarak ele alınabilir mi?
JoeBrockhaus

1
Teşekkür ederim! Bu benim sorunumu çözdü. Bu basit ifade benim sorunumdu, "Olay işleyicileri yalnızca şu anda seçili öğelere bağlıdır; kodunuzun çağrıldığı anda sayfada bulunmaları gerekir ..."
Dennis Fazekas

216

Bu, herhangi bir kütüphane veya eklenti içermeyen saf bir JavaScript çözümüdür:

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

nerede hasClassolduğunu

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

Live demo

Kredi Dave ve Sime Vidas'a gidiyor

Daha modern JS kullanarak hasClassşu şekilde uygulanabilir:

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


6
Bölmek yerine Element.classList kullanabilirsiniz
Eugen Konkov

2
@EugenKonkov Element.classList, eski tarayıcılarda desteklenmez. Örneğin, IE <9.
Ram Patra

2
JQuery yerine vanilya komut dosyası kullanarak işlerin nasıl yapılacağı hakkında güzel bir makale - toddmotto.com/…
Ram Patra

2
köpürmeye ne dersin? İlgilendiğiniz öğenin alt öğesinde tıklama etkinliği gerçekleşirse ne olur?
Andreas Trantidis

73

Nesneleri oluştururken etkinlik ekleyebilirsiniz. Aynı olayları farklı zamanlarda birden çok nesneye ekliyorsanız, adlandırılmış bir işlev oluşturmak doğru yol olabilir.

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

49

Etkinlik bağlama çağrınızı bir işleve sarın ve ardından iki kez çağırın: bir kez hazır belge üzerinde ve bir kez de etkinliğinizden sonra yeni DOM öğeleri ekler. Bunu yaparsanız, aynı etkinliği mevcut öğelere iki kez bağlamaktan kaçınmak istersiniz, böylece mevcut etkinlikleri ya da (daha iyisi) yalnızca yeni oluşturulan DOM öğelerine bağlanmanız gerekir. Kod şöyle görünecektir:

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

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

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

2
Bu yazı gerçekten aynı formu yüklediğim ve 1,2,4,8,16 ... gönderimleri aldığım bir sorunu kavramamı sağladı. .Live () kullanmak yerine, sadece .load () geri çağrıda .bind () kullandım. Sorun çözüldü. Teşekkürler!
Thomas McCabe

42

.live()Bunun yerine kullanmaya çalışın .bind(); .live()bağlayacaktır .hoverAjax isteği yürütür sonra onay kutusunu.


32
Yöntem live()1.7 sürümünde kaldırıldı onve 1.9 sürümünde silindi.
chridam

27

Dinamik olarak oluşturulan öğeler üzerinde olay bağlama

Tek eleman:

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

Alt Öğe:

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

Eklendi dikkat edin *. Bu öğenin tüm alt öğeleri için bir etkinlik tetiklenir.

Ben farkettim ki:

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

Artık çalışmıyor, ama daha önce de çalışıyordu. Google CDN'den jQuery kullanıyorum , ancak değiştirip değiştirmediklerini bilmiyorum.


Yeap ve diyorlar (document.body), atalarının neredeyse her şey olabileceğini söylüyor
MadeInDreams

25

Öğeleri (yeni oluşturulanları bile) onclick olayı gibi olaylara ve işleyicilere bağlamak için live () yöntemini kullanabilirsiniz.

İşte live () yönteminin yeni oluşturulan öğeleri bile olaylara nasıl bağladığını görebileceğiniz, yazdığım örnek bir kod:

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

22

Seçiciyi kullanmayı tercih ederim ve belgeye uygularım.

Bu, belgeye bağlanır ve sayfa yüklendikten sonra oluşturulacak öğelere uygulanabilir.

Örneğin:

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

2
seçici $ ile çevrelenmemelidir, bu nedenle doğru biçim $ (document) .on ("click", "selector", function () {// Burada kodunuz}) olacaktır;
otopilot

1
Bir jQuery nesnesini selectordeğişkenin etrafına sarmak da anlamsızdır , ya doğrudan bir argümana iletebileceğiniz bir dize veya Element nesnesi içermesi gerektiğindeon()
Rory McCrossan

20

Başka bir çözüm, öğeyi oluştururken dinleyiciyi eklemektir. Dinleyiciyi gövdeye koymak yerine, dinleyiciyi oluşturduğunuz anda öğeye koyarsınız:

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

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


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

Kodunuz 1 hata içeriyor: myElement.append('body');olmalıdır myElement.appendTo('body');. Öte yandan, değişkenin daha fazla kullanılmasına gerek yoksa, myElementbu şekilde daha kolay ve daha kısa:$('body').append($('<button/>', { text: 'Go to Google!' }).bind( 'click', goToGoogle));
ddlab

17

Bu şekilde dene -

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

16

Örneğin, öğenin yerleştirildiği "ANA" sınıfına dikkat edin, örneğin,

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

Yukarıdaki senaryoda, jQuery izleyecek ANA nesne "konteyner" dir.

Sonra temelde gibi kabın altındaki elemanlar adlara sahip olacak ul, live select:

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

14

kullanabilirsin

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

veya

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

bu iki yöntem eşdeğerdir ancak farklı bir parametre sırasına sahiptir.

bkz. jQuery Delege Etkinliği


2
delegate()artık kullanımdan kaldırıldı. Bunu kullanma.
Rory McCrossan

14

Öğesini kullanarak dinamik olarak oluşturulduğunda öğeye olay ekleyebilirsiniz jQuery(html, attributes).

JQuery 1.8'den itibaren , herhangi bir jQuery örnek yöntemi (yöntemi jQuery.fn), ikinci parametreye iletilen nesnenin bir özelliği olarak kullanılabilir:

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>


14

Bu olay heyeti tarafından yapılır . Olay sarmalayıcı sınıfı öğeye bağlanacak, ancak seçici sınıf öğesine devredilecek. Bu nasıl çalışır.

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

Not:

wrapper sınıfı eleman ex. belge, gövde veya ambalajınız. Sarıcı zaten mevcut olmalıdır . Ancak, selectorsayfa yükleme sırasında sunulması gerekmez. Daha sonra gelebilir ve olay selector hatasız olarak devam eder .


11

Dinamik olarak oluşturulan öğelerin neden tıklamalara yanıt vermemesinin nedeni:

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>

Geçici bir çözüm olarak, tüm tıklamaları dinlemeniz ve kaynak öğeyi kontrol etmeniz gerekir:

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>

Buna "Etkinlik Delegasyonu" denir. İyi haber, jQuery'de yerleşik bir özellik :-)

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>


10

Herhangi p var Arent olay bağlı olduğu anda ve sayfanızın eğer dinamik unsurları oluşturarak sınıf adı ile düğmeye zaten var olan bir ebeveyne olayı bağlamak istiyorum

$(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>


7

Etkinliği zaten var olan bir ebeveyne bağlama:

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


3

Olay dinleyicilerinin, bir documentdüzey olay dinleyicisine komut dosyası yazmak yerine modüler bir işlevle dağıtılmasını tercih ederim . Yani, aşağıdaki gibi yapıyorum. Not: Aynı olay dinleyicisine sahip bir öğeye gereğinden fazla abone olamazsınız, bu yüzden bir dinleyiciyi bir kereden fazla takma konusunda endişelenmeyin - yalnızca bir çubuk.

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
}


Bu uygulamayı tercih ediyorum; Sadece bir geri arama yapmak zorundayım
William

3

Elemanlar oluşturmak ve olayları bağlamak için başka bir esnek çözüm ( kaynak )

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

Not: Bu, her öğe için bir olay işleyici örneği oluşturur (döngülerde kullanıldığında performansı etkileyebilir)


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

3
Bu kod snippet'i sorunu çözebilir, ancak soruyu neden veya nasıl yanıtladığını açıklamaz. Lütfen gönderinizin kalitesini artırmaya gerçekten yardımcı olduğu için kodunuz için bir açıklama ekleyin. Gelecekte okuyucular için soruyu cevapladığınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceğini unutmayın.
Palec

0

Dinamik olarak eklenen unsurlarda sorunsuz bir şekilde çalışmak $.bindve $.unbindçalışmak için bir çözüm arıyordum .

On () ' da olduğu gibi , olayları eklemek için hile yapar, geldiklerimde sahte bir bağ oluşturmak için:

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

// unbind the click
$('body').on('click', 'button.send', function(){} );

Bağlama çalışmıyor, bu sadece boş bir işleve işaret eden başka bir olay ekliyor ...
Fabian Bigler
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.