Öğenin ne zaman görünür hale geldiği için olay dinleyicisi?


115

Bir sayfaya eklenecek bir araç çubuğu oluşturuyorum. dahil edileceği div varsayılan olarak görüntülenecektir: yok . Araç çubuğuma bir olay dinleyicisi koyup, görünür hale geldiğinde onu dinleyerek başlatabilmemin bir yolu var mı? yoksa onu içeren sayfadan bir değişken geçirmem gerekecek mi?

Teşekkürler


Bu cevap yardımcı olur mu? stackoverflow.com/questions/1397251/…
kangax

@kangax, teşekkür ederim. Ancak yaygın olarak uygulanmadığından, tüm olay dinleyicisi fikrini çizip farklı bir yoldan gideceğimi düşünüyorum.
JD Isaacks

JavaScript'te bir "onVisible" etkinliğinin uygulanması için bu yanıta bakın: stackoverflow.com/a/3807340/975097
Anderson Green


Bunu görebilir misiniz lütfen. stackoverflow.com/questions/45429746/…
Martin

Yanıtlar:


8

Javascript olayları Kullanıcı Etkileşimi ile ilgilenir , eğer kodunuz yeterince organize edilmişse, görünürlük değiştiği yerde başlatma işlevini çağırabilmelisiniz (yani myElement.style.displaybirçok yerde değişmemelisiniz , bunun yerine, bunu yapan bir işlevi / yöntemi çağırmalısınız. bu ve isteyebileceğiniz her şey).


8
Fakat görünürlükteki değişikliği nasıl tespit edebilirsiniz (yani, bir öğe görünür hale gelir gelmez bir işlevi çağırın)?
Anderson Green

Sanırım bunu yapamazsın. Değişimi tespit etmeye çalışmak yerine yapacağınız şey, tam olarak nerede provoke edildiğini bilmek ve çağrınızı oraya koymaktır. Görünürlükteki değişiklik, kendi kodunuzun doğrudan sorumlu olduğu bir şey değilse (örneğin, bazı lib) ve bunun meydana geldiği mantık çok uydurma ise, sanırım şansınız kalmadı? :)
maltalef

6
Bu soruya olumsuz oy verdim çünkü verdiği tüm anlamlara rağmen, asıl sorunla ilgisi yok. (Bir karede hiçbirini göstermezsem, tüm alt öğeler görünmez olur)
Sebas

2
@Sebas, burada çocukların görünürlüğünün neden önemli olduğunu gerçekten anlamıyorum. Her neyse, cevap sizin için yararlı değilse (her ne olursa olsun), ancak çoğu programcı için bir çözüme (veya neden bir çözüm olmadığına dair açıklamaya) işaret ediyorsa, benim mütevazı görüşüme göre hala geçerli bir cevaptır. Diğer cevaplardan birini daha iyi seviyorsanız (özellikle daha sonra, teknoloji geliştiğinde ve yeni seçenekler ortaya çıktığında verilen cevap), doğru cevabı değiştirme talebinin olumsuz oylamadan daha uygun olacağına inanıyorum. Her durumda,
uyarı

2
@figha, çocuklar değil, ancak izlediğiniz öğe görüntülenen bir karenin içindeyse = yok, hiçbir işaretiniz olmayacak.
Sebas

67

Gelecekte, aradığınız şey, yeni HTML Intersection Observer API'sidir. Hedef olarak adlandırılan bir öğe, aygıt görünüm alanıyla veya belirli bir öğeyle kesiştiğinde çağrılan bir geri aramayı yapılandırmanıza olanak tanır. Chrome, Firefox ve Edge'in son sürümlerinde mevcuttur. Daha fazla bilgi için https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API adresine bakın .

Ekranı gözlemlemek için basit kod örneği: yok anahtarlama:

// Start observing visbility of element. On change, the
//   the callback is called with Boolean visibility as
//   argument:

respondToVisibility(element, callback) {
  var options = {
    root: document.documentElement
  }

  var observer = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
      callback(entry.intersectionRatio > 0);
    });
  }, options);

  observer.observe(element);
}

Eylemde: https://jsfiddle.net/elmarj/u35tez5n/5/


2
> Intersection Observer API, hedef olarak adlandırılan bir öğe aygıt görüntü alanıyla veya belirli bir öğeyle kesiştiğinde çağrılan bir geri çağrıyı yapılandırmanıza olanak tanır;
hala

1
InteractionObserver'ın şu anda Safari'de çalışmadığını unutmayın. caniuse.com/#feat=intersectionobserver Görünüşe göre devam eden bir yama var. bugs.webkit.org/show_bug.cgi?id=159475
Pic Mickael

8
IE'nin böyle havalı bir şeye destek vermemesi ne zaman hayatlarımızı mahvetmeyi bırakacak?
Peter Moore

5
Desteklemeye çalışmayı bırakır bırakmaz @PeterMoore. Sadece yapma.
johny neden

4
LOL. Bazen bu bizim kararımız değil.
Peter Moore

45
var targetNode = document.getElementById('elementId');
var observer = new MutationObserver(function(){
    if(targetNode.style.display != 'none'){
        // doSomething
    }
});
observer.observe(targetNode, { attributes: true, childList: true });

Biraz geç kalmış olabilirim, ancak istenen öğedeki değişiklikleri gözlemlemek için MutationObserver'ı kullanabilirsiniz. Herhangi bir değişiklik olursa, öğenin görüntülenip görüntülenmediğini kontrol etmeniz yeterlidir.


4
Bu, targetNode görüntülenmediğinde çalışmaz, çünkü bir üst öğe görüntülenmez, ancak daha sonra görüntülenir.
Marco Eckstein

Oy verildi! Bunu başka bir stackoverflow yanıtında kullandım: stackoverflow.com/questions/48792245/…
Nick Timmer

Ne yazık ki, bu yalnızca öğede satır içi stilleri kullanırken işe yarar, değişiklik CSS sınıfının değişikliğinin bir sonucu olduğunda değil (önceki durumda muhtemelen tam programatik kontrole sahip olduğunuz göz önüne alındığında bu daha olası bir senaryodur). Sorunu gösteren keman: jsfiddle.net/elmarj/uye62Lxc/4 . Tarz değişikliklerini nasıl gözlemleyeceğiniz hakkında daha kapsamlı bir tartışma için buraya bakın: dev.to/oleggromov/observing-style-changes---d4f
Elmar Jansen

Aslında burada kullanılacak doğru Gözlemci şu olacaktır: IntersectionObserver- stackoverflow.com/a/52627221/2803743
kano

Bu çözüm, bir öğeyi açıp kapatmak istediğinizde ve bu öğe üzerinde doğrudan kontrolünüz olmadığında ve görüntülenen değer değişikliğine tepki vermek istediğinizde kullanışlıdır
Eran Goldin

15

En az bir yol var ama bu pek iyi bir yol değil. Öğede aşağıdaki gibi değişiklikler için anket yapabilirsiniz:

var previous_style,
    poll = window.setInterval(function()
{
    var current_style = document.getElementById('target').style.display;
    if (previous_style != current_style) {
        alert('style changed');
        window.clearInterval(poll);
    } else {
        previous_style = current_style;
    }
}, 100);

DOM standardı ayrıca mutasyon olaylarını da belirtir , ancak bunları kullanma şansım hiç olmadı ve ne kadar iyi desteklendiklerinden emin değilim. Onları şu şekilde kullanırsın:

target.addEventListener('DOMAttrModified', function()
{
    if (e.attrName == 'style') {
        alert('style changed');
    }
}, false);

Bu kod aklımın ucunda, bu yüzden işe yarayıp yaramayacağından emin değilim.

En iyi ve en kolay çözüm, hedefinizi görüntüleyen işlevde bir geri aramaya sahip olmaktır.


1
İlginç, teşekkürler. Birkaç yıl sonra, DOMAttrModified'ın durumu değişti: "Kullanımdan kaldırıldı. Bu özellik Web standartlarından kaldırıldı. Bazı tarayıcılar hala desteklese de, bırakılma sürecindedir." (Mozilla)
BurninLeo


14

Aynı sorunu yaşadım ve sitemizde çözmek için bir jQuery eklentisi oluşturdum.

https://github.com/shaunbowe/jquery.visibilityChanged

Örneğinize göre bunu nasıl kullanacağınız aşağıda açıklanmıştır:

$('#contentDiv').visibilityChanged(function(element, visible) {
    alert("do something");
});

4
Bu çözüm .is(':visible')ile birlikte kullanır setTimeout.
Hp93

7

@Figha'nın dediği gibi, eğer bu kendi web sayfanızsa , öğeyi görünür hale getirdikten sonra çalıştırmanız gereken her şeyi çalıştırmalısınız.

Ancak, soruyu yanıtlamak amacıyla (ve bunun yaygın bir kullanım durumu olduğu Chrome veya Firefox Uzantıları yapan herkes ), Mutation Summary ve Mutation Observer , DOM değişikliklerinin olayları tetiklemesine izin verecektir.

Örneğin data-widget, DOM'a eklenen özniteliğe sahip bir öğe için bir olay tetikleme . Bu mükemmel örneği David Walsh'un blogundan ödünç alarak :

var observer = new MutationObserver(function(mutations) {
    // For the sake of...observation...let's output the mutation to console to see how this all works
    mutations.forEach(function(mutation) {
        console.log(mutation.type);
    });    
});

// Notify me of everything!
var observerConfig = {
    attributes: true, 
    childList: true, 
    characterData: true 
};

// Node, config
// In this case we'll listen to all changes to body and child nodes
var targetNode = document.body;
observer.observe(targetNode, observerConfig);

Yanıtlar içerir added, removed, valueChangedve daha fazlası . valueChangeddahil olmak üzere tüm özellikleri içerir display.


Muhtemelen ne zaman ekranda olduğunu bilmek istediği içindir. Yapıyorum, sadece olumsuz oy verenin aynı nedene sahip olduğunu varsayabilirim.
Dave Hillier

Soruyu cevaplamıyor ve yalnızca bağlantı göndermek tavsiye edilmiyor.
Alex Holsgrove

@AlexHolsgrove Bağlantıdan bir örnek ekledim. Poster sayfaya bir araç çubuğu eklemekten bahsettiğinden, üçüncü taraf bir sayfaya bir araç çubuğu ekliyor ve DOM'a bir öğenin eklenmesini bekliyor gibi görünüyor, bu durumda Mutations en iyi API'dir.
mikemaccana

Bunun, mutasyon gözlem sürecinde "görünebilirliğin" nereden geldiğini açıklayan kısmı hala kapsamadığını unutmayın.
Mike 'Pomax' Kamermans


3

DOMAttrModified olay dinleyici tarayıcı desteğiyle ilgili yorum yapmak için:

Çapraz tarayıcı desteği

Bu olaylar, farklı tarayıcılarda tutarlı bir şekilde uygulanmaz, örneğin:

  • Sürüm 9'dan önceki IE, mutasyon olaylarını hiç desteklemiyordu ve bazılarını sürüm 9'da doğru şekilde uygulamıyor (örneğin, DOMNodeInserted)

  • WebKit, DOMAttrModified'ı desteklemiyor (bkz. Webkit hatası 8191 ve geçici çözüm)

  • "mutasyon adı olayları", yani DOMElementNameChanged ve DOMAttributeNameChanged Firefox'ta (sürüm 11'den itibaren) ve muhtemelen diğer tarayıcılarda desteklenmez.

Kaynak: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events


-2

çözümüm:

; (function ($) {
$.each([ "toggle", "show", "hide" ], function( i, name ) {
    var cssFn = $.fn[ name ];
    $.fn[ name ] = function( speed, easing, callback ) {
        if(speed == null || typeof speed === "boolean"){
            var ret=cssFn.apply( this, arguments )
            $.fn.triggerVisibleEvent.apply(this,arguments)
            return ret
        }else{
            var that=this
            var new_callback=function(){
                callback.call(this)
                $.fn.triggerVisibleEvent.apply(that,arguments)
            }
            var ret=this.animate( genFx( name, true ), speed, easing, new_callback )
            return ret
        }
    };
});

$.fn.triggerVisibleEvent=function(){
    this.each(function(){
        if($(this).is(':visible')){
            $(this).trigger('visible')
            $(this).find('[data-trigger-visible-event]').triggerVisibleEvent()
        }
    })
}
})(jQuery);

Örneğin:

if(!$info_center.is(':visible')){
    $info_center.attr('data-trigger-visible-event','true').one('visible',processMoreLessButton)
}else{
    processMoreLessButton()
}

function processMoreLessButton(){
//some logic
}

5
Herkese orijinal jQuery kodunu kullandığınızı söylemelisiniz, bu daha fazla güven
uyandıracaktır

1
"çözümüm". Bu adamdaki sinir.
André Silva

@ AndréSilva Belki jQuery yazdı. : O
Andrew
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.