Ereignis-Listener, wenn das Element sichtbar wird?

112

Ich erstelle eine Symbolleiste, die in eine Seite aufgenommen wird. Das Div, in das es aufgenommen werden soll, wird standardmäßig angezeigt: none . Gibt es eine Möglichkeit, einen Ereignis-Listener in meine Symbolleiste einzufügen, um zu warten, wann er sichtbar wird, damit er initialisiert werden kann? oder muss ich ihm eine Variable von der enthaltenden Seite übergeben?

Vielen Dank

JD Isaacks
quelle
Hilft diese Antwort? stackoverflow.com/questions/1397251/…
kangax
@ Kangax, danke. Aber da es nicht weit verbreitet ist, denke ich, dass ich die gesamte Idee des Event-Listeners zerkratzen und einen anderen Weg gehen werde.
JD Isaacks
Siehe diese Antwort für eine Implementierung eines "onVisible" -Ereignisses in JavaScript: stackoverflow.com/a/3807340/975097
Anderson Green
Könnte das bitte sehen. stackoverflow.com/questions/45429746/…
V SH

Antworten:

8

Javascript- Ereignisse befassen sich mit Benutzerinteraktion . Wenn Ihr Code ausreichend organisiert ist, sollten Sie in der Lage sein, die Initialisierungsfunktion an derselben Stelle aufzurufen, an der sich die Sichtbarkeit ändert (dh Sie sollten sich nicht myElement.style.displayan vielen Stellen ändern , sondern eine Funktion / Methode aufrufen, die dies tut dies und alles andere, was Sie vielleicht wollen).

Maltalef
quelle
8
Aber wie könnten Sie die Änderung der Sichtbarkeit erkennen (dh eine Funktion aufrufen, sobald ein Element sichtbar wird)?
Anderson Green
Ich denke, das kannst du nicht. Was Sie tun würden, anstatt zu versuchen, die Änderung zu erkennen, ist genau zu wissen, wo sie provoziert wird, und Ihren Anruf dort zu tätigen. Wenn die Änderung der Sichtbarkeit nicht direkt für Ihren eigenen Code verantwortlich ist (z. B. eine Bibliothek) und die Logik, nach der dies geschieht, sehr ausgeklügelt ist, haben Sie wahrscheinlich kein Glück? :)
Maltalef
6
Ich habe diese Frage abgelehnt, weil sie trotz des Sinns für das eigentliche Problem irrelevant ist. (Wenn ich keine auf einem Rahmen anzeige, werden alle untergeordneten Elemente unsichtbar)
Sebas
2
@Sebas, ich verstehe nicht wirklich, warum die Sichtbarkeit der Kinder hier wichtig ist. Wie auch immer, wenn die Antwort für Ihren speziellen Fall nicht nützlich war (was auch immer es sein mag), aber für die meisten Programmierer auf eine Lösung (oder eine Erklärung, warum es keine Lösung gibt) verweist, ist sie meiner bescheidenen Meinung nach immer noch eine gültige Antwort. Wenn Ihnen eine der anderen Antworten besser gefällt (insbesondere eine, die zu einem späteren Zeitpunkt gemacht wurde, als sich die Technologie verbesserte und neue Optionen verfügbar wurden), wäre eine Aufforderung zur Änderung der richtigen Antwort meiner Meinung nach angemessener als eine Abwertung. Auf jeden Fall danke für das Heads-up :)
Maltalef
2
@figha, nicht die Kinder, aber wenn sich das Element, das Sie beobachten, in einem Frame befindet, der angezeigt wird = keine, haben Sie keine Anzeichen dafür.
Sebas
66

In Zukunft ist die neue HTML Intersection Observer-API genau das, wonach Sie suchen. Sie können einen Rückruf konfigurieren, der immer dann aufgerufen wird, wenn ein Element, das als Ziel bezeichnet wird, entweder das Geräteansichtsfenster oder ein bestimmtes Element schneidet. Es ist in den neuesten Versionen von Chrome, Firefox und Edge verfügbar. Weitere Informationen finden Sie unter https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API .

Einfaches Codebeispiel zur Beobachtung der Anzeige: keine Umschaltung:

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

In Aktion: https://jsfiddle.net/elmarj/u35tez5n/5/

Elmar Jansen
quelle
2
> Mit der Intersection Observer-API können Sie einen Rückruf konfigurieren, der immer dann aufgerufen wird, wenn ein Element, das als Ziel bezeichnet wird, entweder das Geräteansichtsfenster oder ein bestimmtes Element schneidet.
stil
1
Beachten Sie, dass der InteractionObserver derzeit in Safari nicht funktioniert. caniuse.com/#feat=intersectionobserver Es sieht so aus, als ob ein Patch in Bearbeitung ist. bugs.webkit.org/show_bug.cgi?id=159475
Pic Mickael
7
Wann wird die mangelnde Unterstützung des IE für so etwas Cooles aufhören, unser Leben zu ruinieren?
Peter Moore
5
@PeterMoore, sobald Sie aufhören, es zu unterstützen. Tu es einfach nicht.
Johny, warum
3
LOL. Manchmal ist es nicht unsere Entscheidung.
Peter Moore
44
var targetNode = document.getElementById('elementId');
var observer = new MutationObserver(function(){
    if(targetNode.style.display != 'none'){
        // doSomething
    }
});
observer.observe(targetNode, { attributes: true, childList: true });

Ich bin vielleicht etwas spät dran, aber Sie können einfach den MutationObserver verwenden, um Änderungen am gewünschten Element zu beobachten. Wenn sich etwas ändert, müssen Sie nur überprüfen, ob das Element angezeigt wird.

user3588429
quelle
4
Dies funktioniert nicht, wenn der Zielknoten nicht angezeigt wird, da ein Vorfahr nicht angezeigt wird, aber dann angezeigt wird.
Marco Eckstein
Upvoted! Ich habe dies in einer anderen Stackoverflow-Antwort verwendet: stackoverflow.com/questions/48792245/…
Nick Timmer
Leider funktioniert dies nur, wenn Inline-Stile für das Element verwendet werden, nicht, wenn die Änderung auf eine Änderung der CSS-Klasse zurückzuführen ist (was das wahrscheinlichere Szenario ist, da Sie in der vorherigen Situation wahrscheinlich bereits die volle programmatische Kontrolle haben). Geige, die das Problem zeigt: jsfiddle.net/elmarj/uye62Lxc/4 . Weitere Informationen
Elmar Jansen
Tatsächlich wäre der richtige Beobachter, der hier verwendet werden soll, ein IntersectionObserver- stackoverflow.com/a/52627221/2803743
kano
Diese Lösung ist nützlich, wenn Sie ein Element ein- und ausschalten möchten und keine direkte Kontrolle über dieses Element haben und auf die Änderung des Anzeigewerts reagieren möchten
Eran Goldin
15

Es gibt mindestens einen Weg, aber keinen sehr guten. Sie können das Element einfach nach folgenden Änderungen abfragen:

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

Der DOM-Standard spezifiziert auch Mutationsereignisse , aber ich hatte nie die Möglichkeit, sie zu verwenden, und ich bin mir nicht sicher, wie gut sie unterstützt werden. Sie würden sie so verwenden:

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

Dieser Code ist mir ein Rätsel, daher bin ich mir nicht sicher, ob er funktionieren würde.

Die beste und einfachste Lösung wäre ein Rückruf in der Funktion zur Anzeige Ihres Ziels.

slikts
quelle
1
Interessant, danke. Einige Jahre später hat sich der Status von DOMAttrModified geändert: "Veraltet. Diese Funktion wurde aus den Webstandards entfernt. Einige Browser unterstützen sie möglicherweise noch, werden jedoch derzeit gelöscht." (Mozilla)
BurninLeo
MutationObserver ist das neue neue.
mindplay.dk
14

Ich hatte das gleiche Problem und habe ein jQuery-Plugin erstellt, um es für unsere Site zu lösen.

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

So würden Sie es anhand Ihres Beispiels verwenden:

$('#contentDiv').visibilityChanged(function(element, visible) {
    alert("do something");
});
Shaun Bowe
quelle
4
Diese Lösung verwendet .is(':visible')zusammen mit setTimeout.
Hp93
7

Wie @figha sagt, sollten Sie , wenn dies Ihre eigene Webseite ist , einfach alles ausführen, was Sie ausführen müssen, nachdem Sie das Element sichtbar gemacht haben.

Für die Beantwortung der Frage (und für alle, die Chrome- oder Firefox-Erweiterungen erstellen , sofern dies ein häufiger Anwendungsfall ist) ermöglichen Mutation Summary und Mutation Observer jedoch, dass DOM-Änderungen Ereignisse auslösen.

Auslösen eines Ereignisses für ein Element mit data-widgetAttribut, das dem DOM hinzugefügt wird. Ausleihen dieses hervorragenden Beispiels aus David Walshs Blog :

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

Antworten umfassen added, removed, valueChangedund mehr . valueChangedenthält alle Attribute, einschließlich displayusw.

Mikemaccana
quelle
Wahrscheinlich, weil er wissen will, wann es tatsächlich auf dem Bildschirm ist. Ich kann nur davon ausgehen, dass der Downvoter den gleichen Grund hat.
Dave Hillier
Beantwortet die Frage nicht und es wird nicht empfohlen, nur Links zu veröffentlichen.
Alex Holsgrove
@AlexHolsgrove Ich habe ein Beispiel aus dem Link hinzugefügt. Da das Poster über das Hinzufügen einer Symbolleiste zur Seite spricht, scheint es, als würden sie einer Seite eines Drittanbieters eine Symbolleiste hinzufügen und darauf warten, dass dem DOM ein Element hinzugefügt wird. In diesem Fall ist Mutationen die beste API.
Mikemaccana
Beachten Sie, dass dies immer noch nicht den Teil abdeckt, der erklärt, wo im Mutationsbeobachtungsprozess "Sichtbarkeit"
eintritt
3

Nur um die Unterstützung des DOMAttrModified Event Listener-Browsers zu kommentieren:

Browserübergreifende Unterstützung

Diese Ereignisse werden in verschiedenen Browsern nicht konsistent implementiert. Beispiel:

  • IE vor Version 9 hat die Mutationsereignisse überhaupt nicht unterstützt und einige davon in Version 9 nicht korrekt implementiert (z. B. DOMNodeInserted).

  • WebKit unterstützt DOMAttrModified nicht (siehe Webkit-Fehler 8191 und die Problemumgehung).

  • "Mutationsnamenereignisse", dh DOMElementNameChanged und DOMAttributeNameChanged, werden in Firefox (ab Version 11) und wahrscheinlich auch in anderen Browsern nicht unterstützt.

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

Josh
quelle
-2

meine Lösung:

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

beispielsweise:

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

function processMoreLessButton(){
//some logic
}
user2699000
quelle
5
Sie sollten jedem sagen, dass Sie den ursprünglichen Code von jQuery verwendet haben, dies würde mehr Vertrauen schaffen;)
aemonge
1
"meine Lösung". Der Nerv an diesem Kerl.
André Silva
@ AndréSilva Vielleicht hat er jQuery geschrieben. : O
Andrew