Listener di eventi per quando l'elemento diventa visibile?


113

Sto costruendo una barra degli strumenti che verrà inclusa in una pagina. il div in cui verrà incluso verrà visualizzato per impostazione predefinita : nessuno . C'è un modo per mettere un listener di eventi sulla mia barra degli strumenti per ascoltare quando diventa visibile in modo che possa inizializzarsi? o dovrò passargli una variabile dalla pagina che lo contiene?

Grazie



@kangax, grazie. Ma poiché non è ampiamente implementato, penso che scalderò l'intera idea dell'ascoltatore di eventi e seguirò una strada diversa.
JD Isaacks,

Vedi questa risposta per un'implementazione di un evento "onVisible" in JavaScript: stackoverflow.com/a/3807340/975097
Anderson Green


Potrebbe vederlo per favore. stackoverflow.com/questions/45429746/…
Martin

Risposte:


8

Gli eventi Javascript riguardano l' interazione utente , se il tuo codice è organizzato abbastanza dovresti essere in grado di chiamare la funzione di inizializzazione nello stesso punto in cui cambia la visibilità (cioè non dovresti cambiare myElement.style.displayin molti posti, invece, chiama una funzione / metodo che lo fa questo e qualsiasi altra cosa tu possa desiderare).


8
Ma come potresti rilevare il cambiamento di visibilità (cioè chiamare una funzione non appena un elemento diventa visibile)?
Anderson Green

Penso che non puoi farlo. Quello che faresti invece di cercare di rilevare il cambiamento, è sapere esattamente dove è stato provocato e mettere lì la tua chiamata. Se il cambiamento di visibilità non è qualcosa di cui il tuo codice è direttamente responsabile (ad esempio alcune librerie) e la logica con cui ciò accade è molto artificiosa, immagino che tu sia sfortunato? :)
maltalef

6
Ho svalutato questa domanda perché, nonostante tutto il senso che ha, è irrilevante per il problema reale. (se non visualizzo nessuno su un frame, tutti gli elementi figli diventano invisibili)
Sebas

2
@Sebas, non capisco davvero perché la visibilità dei bambini sia importante qui. Ad ogni modo, se la risposta non è stata utile per il tuo caso particolare (qualunque essa sia) ma punta a una soluzione (o una spiegazione perché non c'è una soluzione) per la maggior parte dei programmatori, è comunque una risposta valida a mio modesto parere. Se ti piace di più una delle altre risposte (specialmente quella che è stata fatta in un secondo momento, quando la tecnologia è migliorata e sono diventate disponibili nuove opzioni), credo che una richiesta di cambiare la risposta corretta sarebbe più appropriata di un voto negativo. In ogni caso, grazie per l'
avviso

2
@figha, non i bambini, ma se l'elemento che stai guardando è in un frame visualizzato = nessuno, non ne avrai alcun segno.
Sebas

66

In futuro, la nuova API HTML Intersection Observer è ciò che stai cercando. Ti consente di configurare un callback che viene chiamato ogni volta che un elemento, chiamato target, interseca il viewport del dispositivo o un elemento specificato. È disponibile nelle ultime versioni di Chrome, Firefox e Edge. Vedi https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API per maggiori informazioni.

Semplice esempio di codice per l'osservazione del display: nessuna commutazione:

// 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 azione: https://jsfiddle.net/elmarj/u35tez5n/5/


2
> L'API Intersection Observer consente di configurare un callback che viene chiamato ogni volta che un elemento, chiamato target, interseca la finestra del dispositivo o un elemento specificato;
stil

1
Nota che InteractionObserver non funziona su Safari al momento. caniuse.com/#feat=intersectionobserver Sembra che sia in corso una patch. bugs.webkit.org/show_bug.cgi?id=159475
Pic Mickael

8
Quand'è che la mancanza di supporto di IE per qualcosa di interessante come questo smetterà di rovinare le nostre vite?
Peter Moore

5
@PeterMoore non appena smetti di provare a supportarlo. Basta non farlo.
johny why

4
LOL. A volte non è una nostra decisione.
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 });

Potrei essere un po 'in ritardo, ma potresti semplicemente usare MutationObserver per osservare eventuali modifiche sull'elemento desiderato. In caso di modifiche, dovrai solo controllare se l'elemento è visualizzato.


4
Questo non funziona quando targetNode non viene visualizzato perché un antenato non viene visualizzato ma poi viene visualizzato.
Marco Eckstein

Upvoted! L'ho usato in un'altra risposta stackoverflow: stackoverflow.com/questions/48792245/…
Nick Timmer

Sfortunatamente, questo funziona solo quando si usano gli stili inline sull'elemento, non quando la modifica è il risultato di una modifica della classe CSS (che è lo scenario più probabile, dato che nella prima situazione probabilmente si ha già il pieno controllo programmatico). Violino che mostra il problema: jsfiddle.net/elmarj/uye62Lxc/4 . Vedi qui per una discussione più completa su come osservare i cambiamenti di stile: dev.to/oleggromov/observing-style-changes---d4f
Elmar Jansen

In realtà l'osservatore corretto da utilizzare qui sarebbe un IntersectionObserver- stackoverflow.com/a/52627221/2803743
kano

Questa soluzione è utile quando si desidera attivare e disattivare un elemento e non si ha il controllo diretto di quell'elemento e si desidera reagire alla modifica del valore visualizzato
Eran Goldin

15

C'è almeno un modo, ma non è molto buono. Potresti semplicemente eseguire il polling dell'elemento per modifiche come questa:

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

Lo standard DOM specifica anche gli eventi di mutazione , ma non ho mai avuto la possibilità di usarli e non sono sicuro di quanto siano supportati. Li useresti in questo modo:

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

Questo codice è fuori dalla mia testa, quindi non sono sicuro che funzionerebbe.

La soluzione migliore e più semplice sarebbe quella di avere una richiamata nella funzione che mostra il tuo obiettivo.


1
Interessante, grazie. Alcuni anni dopo, lo stato di DOMAttrModified è cambiato: "Deprecato. Questa funzione è stata rimossa dagli standard Web. Sebbene alcuni browser possano ancora supportarla, è in procinto di essere abbandonata." (Mozilla)
BurninLeo

MutationObserver è il nuovo nuovo.
mindplay.dk

14

Ho avuto lo stesso problema e ho creato un plugin jQuery per risolverlo per il nostro sito.

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

Ecco come lo useresti in base al tuo esempio:

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

4
Questa soluzione utilizza .is(':visible')insieme a setTimeout.
Hp93

7

Come dice @figha, se questa è la tua pagina web , dovresti semplicemente eseguire tutto ciò di cui hai bisogno per eseguire dopo aver reso visibile l'elemento.

Tuttavia, ai fini della risposta alla domanda (e chiunque crei estensioni per Chrome o Firefox , dove questo è un caso d'uso comune), Riepilogo delle mutazioni e Osservatore delle mutazioni consentiranno alle modifiche DOM di attivare eventi.

Ad esempio, l'attivazione di un evento per un elemento con un data-widgetattributo aggiunto al DOM. Prendendo in prestito questo eccellente esempio dal blog di David Walsh :

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

Le risposte sono added, removed, valueChangede altro ancora . valueChangedinclude tutti gli attributi, inclusi displayecc.


Probabilmente perché vuole sapere quando è effettivamente sullo schermo. Sì, posso solo presumere che il downvoter abbia lo stesso motivo.
Dave Hillier

Non risponde alla domanda e non è consigliato pubblicare solo link.
Alex Holsgrove

@AlexHolsgrove Ho aggiunto un esempio, dal collegamento. Poiché il poster parla dell'aggiunta di una barra degli strumenti alla pagina, sembra che stia aggiungendo una barra degli strumenti a una pagina di terze parti e in attesa che un elemento venga aggiunto al DOM, nel qual caso Mutations è la migliore API.
mikemaccana

Si noti che questo ancora non copre la parte che spiega dove entra in gioco la "visibilità" nel processo di osservazione della mutazione.
Mike 'Pomax' Kamermans


3

Solo per commentare il supporto del browser del listener di eventi DOMAttrModified:

Supporto cross-browser

Questi eventi non vengono implementati in modo coerente nei diversi browser, ad esempio:

  • IE prima della versione 9 non supportava affatto gli eventi di mutazione e non ne implementava alcuni correttamente nella versione 9 (ad esempio, DOMNodeInserted)

  • WebKit non supporta DOMAttrModified (vedere il bug del webkit 8191 e la soluzione alternativa)

  • Gli "eventi del nome di mutazione", ovvero DOMElementNameChanged e DOMAttributeNameChanged non sono supportati in Firefox (a partire dalla versione 11) e probabilmente anche in altri browser.

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


-2

la mia soluzione:

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

per esempio:

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

function processMoreLessButton(){
//some logic
}

5
Dovresti dire a tutti che hai usato il codice jQuery originale, ispirerebbe più fiducia;)
aemonge

1
"la mia soluzione". Il coraggio di questo ragazzo.
André Silva

@ AndréSilva Forse ha scritto jQuery. : O
Andrew
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.