.append'den sonra jQuery işlevi


92

JQuery .appendtamamen tamamlandıktan sonra bir işlev nasıl çağrılır ?

İşte bir örnek:

$("#root").append(child, function(){
   // Action after append is completly done
});

Sorun: Karmaşık bir DOM yapısı eklendiğinde, append işlevi geri çağırma içindeki kök öğenin yeni boyutunun hesaplanması yanlıştır. Varsayımlar, DOM'un hala tam olarak yüklenmediği, eklenen karmaşık DOM'un yalnızca ilk alt öğesinin yüklü olduğudur.


İyi zincirleme olayları olmalısınız; append()çok az zaman alır.
Bojangles

stackoverflow.com/q/8840580/176140'a bakın (webkit tarayıcılarda dom 'yeniden akış')
schellmax

Yanıtlar:


71

Burada birçok geçerli cevabınız var ama hiçbiri size neden olduğu gibi çalıştığını gerçekten söylemiyor.

JavaScript'te komutlar, bir zaman aşımı veya aralık kullanarak asenkron olmalarını açıkça belirtmediğiniz sürece, geldikleri sırayla eşzamanlı olarak birer birer çalıştırılır.

Bu, .appendyönteminizin yürütüleceği ve bu yöntem işini bitirene kadar başka hiçbir şeyin (mevcut olabilecek olası zaman aşımlarını veya aralıkları göz ardı ederek) çalışmayacağı anlamına gelir.

Özetlemek gerekirse, .appendeşzamanlı olarak çalışacağından geri aramaya gerek yoktur .


40
Bunların hepsi doğru, ama işte benim sorunum: Karmaşık DOM ekliyorum ve ekledikten hemen sonra yeni kök eleman boyutunu hesaplıyorum, ancak burada yanlış numara aldım. Ve düşünün ki, sorun şudur: DOM içinde hala tam olarak yüklenmemiş, yalnızca birinci alt öğe (.append ("<div id =" child "> <div id =" subChild_with_SIZE "> </div> </div>"))
David Horák

@JinDave, bahsettiğiniz bu boyut nedir ? Çocuk sayısı, ebeveynin boyu veya hesaplamanız gereken şey nedir?
mekwall

1
@ marcus-ekwall jsfiddle.net/brszE/3 Bu sadece yazma yöntemi, kod çalışmıyor
David Horák

22
@ DavidHorák öyleyse neden bu kabul edilen cevap? Değişiklik gerçekleşse bile, kodun, tam yeniden akış 32 ek oyu oldukça şaşırtana kadar engellemeyeceği doğrudur! (Veya bu benim yeniden akışa neden olmamalıdır) [burada] ( stackoverflow.com/questions/ 8840580 /… ) cevherle ilgili olabilir.
Andreas

17
Andreas'a katılıyorum, bu cevap doğru değil. Sorun şu ki, append dönmüş olsa bile, öğe hala DOM'da mevcut olmayabilir (tarayıcıya bağlıdır, bazı tarayıcılarda çalışır, diğerlerinde çalışır). Bir zaman aşımı kullanmak, öğenin DOM'da olacağını hala garanti etmez.
Severun

21

Marcus Ekwall, eklemenin eşzamanlılığı konusunda kesinlikle haklı olsa da, tuhaf durumlarda bazen bir sonraki kod satırı çalıştığında DOM'un tarayıcı tarafından tamamen işlenmediğini de buldum.

Bu senaryoda, shadowdiver çözümleri doğru satırlardadır - .ready kullanarak - ancak aramayı orijinal eklentinize zincirlemek çok daha derli topludur.

$('#root')
  .append(html)
  .ready(function () {
    // enter code here
  });

1
Bu, her durumda kesinlikle yanlış ve yararsızdır. api.jquery.com/ready
Kevin B

Merhaba Kevin, ne şekilde?
Daniel - SDS Group

Eklenen öğeleri, yalnızca ve ancak belge hazır değilse, yalnızca bir ayar zaman aşımı kullanarak elde edeceğinizden daha fazlasını "işlemek" için beklemeye hazır kullanmanın kesinlikle hiçbir faydası yoktur. belge hazırsa, kod eşzamanlı olarak çalıştırılacak ve böylece sıfır yararlı etkiye sahip olacaktır.
Kevin B

Ready'nin eklenen belgenin yüklenmesini bekleyeceğini sanmıyorum, bunun yerine tüm DOM'un yüklenmesini bekleyecek. Bu cevabı yazdığımdan bu yana yaklaşık 3 yıl geçmişti ama sanırım yukarıdaki gölge dalgıçına daha çok yorum yapıyordum ama o sırada yorum yapma imkanım yoktu.
Daniel - SDS Group

1
Aslında bu beklenenden daha iyi çalışıyor. Buradaki diğer cevaplardan daha iyi.
Blue

20

Boyut yeniden hesaplamayla da tamamen aynı problemim var ve saatler süren baş ağrısından sonra .append()kesinlikle senkronize davranmaya katılmıyorum . En azından Google Chrome'da. Aşağıdaki koda bakın.

var input = $( '<input />' );
input.append( arbitraryElement );
input.css( 'padding-left' );

Padding-left özelliği, Firefox'ta doğru bir şekilde alınır, ancak Chrome'da boştur. Sanırım diğer tüm CSS özellikleri gibi. Bazı deneylerden sonra, CSS 'alıcıyı' setTimeout()10 ms gecikmeyle sarmalamaya karar verdim, bunun Çirkin olduğunu bildiğim, ancak Chrome'da çalışan tek kişi. Herhangi biriniz bu sorunu nasıl daha iyi çözebileceğiniz konusunda bir fikriniz varsa çok minnettar olurum.


15
bu bana ÇOK yardımcı oldu: stackoverflow.com/q/8840580/176140 - yani, append () eşzamanlı, ancak DOM güncellemesi değil
schellmax

Bu durumda setTimeout çirkin değildir (sadece 10ms öyledir). "Dom" değiştirme isteğinde bulunduğunuz her seferinde, Chrome, çalıştırmadan önce kodunuzun bitmesini bekler. Yani, item.hide ve ardından item.show çağırırsanız hiçbir şey yapmaz. Yürütme işleviniz bittiğinde, değişikliklerinizi DOM'a uygular. Devam etmeden önce bir "dom" güncellemesini beklemeniz gerekiyorsa, CSS / DOM eyleminizi yapın ve ardından settimeout (function () {sonra ne yapmalı}); çağrısı yapın. Settimeout, vb6'da eski bir "doevents" gibi davranır! Tarayıcıya bekleme görevlerini (DOM güncelleme) yapmasını söyler ve sonra kodunuza geri döner.
foxontherock

.ready()Çok daha iyi ve daha zarif bir çözümden faydalanan cevabı görün .
Mark Carpenter Jr

8

Buradaki tüm cevaplara şaşırıyorum ...

Bunu dene:

window.setTimeout(function() { /* your stuff */ }, 0);

0 zaman aşımına dikkat edin. Bu rastgele bir sayı değil ... anladığım kadarıyla (anlayışım biraz sarsıcı olabilir), biri makro olaylar ve biri mikro olaylar için olmak üzere iki javascript olay kuyruğu var. "Daha geniş" kapsamlı kuyruk, kullanıcı arayüzünü (ve DOM'u) güncelleyen görevleri tutarken, mikro kuyruk hızlı görev türü işlemleri gerçekleştirir.

Ayrıca, bir zaman aşımı ayarlamanın, kodun tam olarak belirtilen değerde çalışacağını garanti etmediğini unutmayın. Bunun yaptığı şey aslında işlevi daha yüksek sıraya (UI / DOM'u işleyen) koyar ve belirtilen zamandan önce çalıştırmaz.

Bu, zaman aşımının 0 olarak ayarlanmasının, onu javascript olay kuyruğunun UI / DOM kısmına, bir sonraki olası fırsatta çalıştırılmak üzere koyacağı anlamına gelir.

Bu, DOM'un önceki tüm kuyruk öğeleriyle güncellendiği anlamına gelir (örneğin, aracılığıyla eklenir $.append(...);ve kodunuz çalıştığında, DOM tamamen kullanılabilir).

(ps - Bunu Secrects of the JavaScript Ninja'dan öğrendim - mükemmel bir kitap: https://www.manning.com/books/secrets-of-the-javascript-ninja )


setTimeout()Yıllardır nedenini bilmeden ekliyorum . Açıklama için teşekkürler!
steampowered

5

Birisi için faydalı olabilecek başka bir varyantım var:

$('<img src="http://example.com/someresource.jpg">').load(function() {
    $('#login').submit();
}).appendTo("body");

1
Bunun kullanımdan kaldırıldığını ve kaldırıldığını düşünenler için, doğru ama yine de ...on('load', function(){ ...
şuraya

5

Aynı problemle karşılaştım ve basit bir çözüm buldum. Ekleme işlevini çağırdıktan sonra hazır bir belge ekleyin.

$("#root").append(child);
$(document).ready(function () {
    // Action after append is completly done
});


Güzel. Bu benim için çalıştı (Gidon ve JSON kullanarak HTML ekliyordum ve tabii ki normal bir belge. Zaten tüm bunlar için çok erken oluyor).
Katharine Osborne

1
@KatharineOsborne Bu, "normal bir document.ready" den farklı değil. document.ready yalnızca belirli bir senaryoda çağrılır, farklı şekilde kullanılması farklı çalışmasını sağlamaz.
Kevin B

Yorum bırakalı bir yıldan fazla zaman geçti, ancak IIRC, buna nerede dediğinizin bağlamı önemlidir (yani bir işlevde). Kod o zamandan beri bir müşteriye aktarıldı, bu yüzden tekrar girmek için ona erişimim yok.
Katharine Osborne

5

Kullanmak MutationObserver, jQuery appendyöntemi için bir geri arama işlevi görebilir :

Bunu başka bir soruda açıkladım ve bu sefer sadece modern tarayıcılar için örnek vereceğim:

// Somewhere in your app:
var observeDOM = (() => {
    var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

    return function(obj, callback){
        if( MutationObserver ){
            // define a new observer
            var obs = new MutationObserver(function(mutations, observer){
                if( mutations[0].addedNodes.length || mutations[0].removedNodes.length )
                    callback(mutations);
            });
            // have the observer observe foo for changes in children
            obs.observe( obj, { childList:true, subtree:true });

            return obs;
        }
    }
})();

//////////////////
// Your code:

// setup the DOM observer (on the appended content's parent) before appending anything
observeDOM( document.body, ()=>{
    // something was added/removed
}).disconnect(); // don't listen to any more changes

// append something
$('body').append('<p>foo</p>');

+1. Tüm cevaplar arasında sizinki en iyisidir. Ancak benim durumumda işe yaramadı, tabloya çeşitli satırlar ekleyerek, çünkü sonsuz bir döngüye giriyor. Tabloyu sıralayan eklenti DOM'u değiştirecek ve böylece gözlemciyi sonsuz kez çağıracaktır.
Azevedo

@Azevedo - neden sonsuz olsun ki? Sonlu olduğundan eminim. yine de, biraz yaratıcı olarak bir sıralama işlevini eklenen bir "etkinlik" satırından ayırabilirsiniz . yollar var.
vsync

Sıralama eklentisi tabloyu sıraladığında gözlemciyi tetikler (dom değiştirildi) ve bu da sıralamayı tekrar tetikler. Şimdi düşünüyorum da ... Tablo satırlarını sayabilirim ve gözlemcinin sıralayıcıyı yalnızca satır sayacı değiştirilirse çağırmasını sağlayabilirim.
Azevedo

3

Bunun iyi yanıtlandığını düşünüyorum, ancak bu "subChild_with_SIZE" konusunu işlemeye biraz daha özgü (eğer bu ebeveynden geliyorsa, ancak onu olabileceği yerden uyarlayabilirsiniz)

$("#root").append(
    $('<div />',{
        'id': 'child'
    })
)
.children()
.last()
.each(function() {
    $(this).append(
        $('<div />',{
            'id': $(this).parent().width()
        })
    );
});

2

$.when($('#root').append(child)).then(anotherMethod());


8
$.whensadece bir vaat nesnesi iade eden nesneler için çalışır
Rifat

çalışıyor ama konsolda hata veriyor .. "o zaman bir işlev değil"
Karan Datwani

1
Bu sadece çalışır çünkü anotherMethod()hemen çağırıyorsunuz .. Geri arama olarak iletilmiyor.
yts

Bu hiçbir anlam ifade etmiyor.
Kevin B

1

Jquery append işlevi bir jQuery nesnesi döndürür, böylece sonunda bir yöntemi etiketleyebilirsiniz

$("#root").append(child).anotherJqueryMethod();

.Append'den sonra bana özel javascript işlevi çağırmam gerekiyor, kök boyutunu yeniden hesaplamam gerekiyor
David Horák

jQuery'yi her yöntemi kullanabilirsiniz, ancak append eşzamanlı bir yöntemdir, bu nedenle bir sonraki satırda ihtiyacınız olan her şeyi yapmak için tamam olmalısınız.
Dve

@JinDave, yeniden hesaplamak için tam olarak neye ihtiyacın var? Çocuk sayısı, ebeveynin boyu veya beden ne anlama geliyor?
mekwall

0

Resimler ve diğer kaynaklar için şunu kullanabilirsiniz:

$(el).one('load', function(){
    // completed
}).each(function() {
    if (this.complete)
        $(this).load();
});

0

En temiz yol, bunu adım adım yapmaktır. Her öğe üzerinden geçiş yapmak için her bir işlevi kullanın. Bu öğe eklenir eklenmez, onu işlemek için sonraki bir işleve aktarın.

    function processAppended(el){
        //process appended element
    }

    var remove = '<a href="#">remove</a>' ;
    $('li').each(function(){
        $(this).append(remove);   
        processAppended(this);    
    });​

-1

Mobil cihazlar için HTML5 kodlarken bu sorunla karşılaştım. Bazı tarayıcı / cihaz kombinasyonları hatalara neden oldu çünkü .append () yöntemi DOM'daki değişiklikleri anında yansıtmadı (JS'nin başarısız olmasına neden oldu).

Bu durum için hızlı ve kirli çözüm:

var appint = setInterval(function(){
    if ( $('#foobar').length > 0 ) {
        //now you can be sure append is ready
        //$('#foobar').remove(); if elem is just for checking
        //clearInterval(appint)
    }
}, 100);
$(body).append('<div>...</div><div id="foobar"></div>');

Aralıklar asla bir kod oluşturucunun bitmesini beklemek için kullanılmamalıdır. Tamamen güvenilmez.
Gabe Hiemstra

-1

Evet olabilir bir ekleme geri arama : Herhangi DOM ekleme fonksiyonu
$myDiv.append( function(index_myDiv, HTML_myDiv){ //.... return child })

JQuery belgelere Kontrolü: http://api.jquery.com/append/
burada Ve pratik, benzer, örnek: http://www.w3schools.com/jquery/ tryit.asp? filename = tryjquery_html_prepend_func


.prepend()W3schools örneğiyle uğraşarak , yöntemi $ ("p") ile değiştirerek 2. parametreyi kontrol edebilirsiniz . Prepend (function (n, pHTML) {return "<b> Bu p öğesi </b> (\" <i > "+ pHTML +" </i> \ ") <b>" + n + "</b> dizinine sahip.";
Pedro Ferreira

1
Bu örneğin amacını açıkça anlamıyorsunuz ... bu, içeriğin eklendiğini söyleyen bir geri arama değil , daha çok eklenecek olanı döndüren bir geri arama işlevi .
vsync

@vsync: kesinlikle. Cevabımı açıkça anlamadın. "çocuk" olduğunu Ne eklenmiş olsa ve değil ekteki zaman.
Pedro Ferreira

-1

Geçenlerde benzer bir sorunla karşılaştım. Benim için çözüm, koleksiyonları yeniden yaratmaktı. Göstermeye çalışayım:

var $element = $(selector);
$element.append(content);

// This Doesn't work, because $element still contains old structure:
$element.fooBar();    

// This should work: the collection is re-created with the new content:
$(selector).fooBar();

Bu yardımcı olur umarım!


Bana yardımcı olmadı. :(
Pal


-2

Bunun en iyi çözüm olmadığını biliyorum, ancak en iyi uygulama:

$("#root").append(child);

setTimeout(function(){
  // Action after append
},100);

8
Bunun iyi bir uygulama olduğunu sanmıyorum. 100 keyfi bir sayıdır ve bir olay daha uzun sürebilir.
JasTonAChair

1
Yanlış yol. Her zaman 100 ms
sürmeyebilir

Bunun neden işe yaradığına dair bir açıklama için burada
cevabıma bakın

1
en azından buradaki .ready yanıtlarından daha iyi bir uygulamadır.
Kevin B

-4
$('#root').append(child);
// do your work here

Append'in geri çağırmaları yoktur ve bu eşzamanlı olarak çalışan koddur - yapılmaması riski yoktur.


3
Bunun gibi çok fazla yorum görüyorum ve bunlar yardımcı olmuyor. @david fells, evet, JS eşzamanlı, ancak DOM'un güncellenmesi için zamana ihtiyacı var. DOM eklenmiş öğelerinizi değiştirmeniz gerekiyorsa ancak öğeler henüz DOM'nuzda oluşturulmadıysa, ekleme yapılsa bile, yeni işleminiz çalışmayacaktır. (Örneğin: $ ['# element']. On ().
NoobishPro

-4
$('#root').append(child).anotherMethod();

1
Beni jQuery işlevi değil, javascript işlevi aramam gerekiyor
David Horák
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.