Écouteur d'événements pour quand l'élément devient visible?


115

Je construis une barre d'outils qui sera incluse dans une page. le div dans lequel il va être inclus s'affichera par défaut : aucun . Existe-t-il un moyen de placer un écouteur d'événements sur ma barre d'outils pour écouter quand il devient visible afin qu'il puisse s'initialiser? ou vais-je devoir lui passer une variable de la page contenant?

Merci


Cette réponse vous aide-t-elle? stackoverflow.com/questions/1397251/…
kangax

@kangax, merci. Mais comme il n'est pas largement mis en œuvre, je pense que je vais rayer l'idée entière de l'auditeur d'événements et emprunter une voie différente.
JD Isaacks

Voir cette réponse pour une implémentation d'un événement "onVisible" dans JavaScript: stackoverflow.com/a/3807340/975097
Anderson Green


Pourrait voir cela s'il vous plaît. stackoverflow.com/questions/45429746/…
Martin

Réponses:


8

Les événements Javascript traitent de l'interaction utilisateur , si votre code est suffisamment organisé, vous devriez pouvoir appeler la fonction d'initialisation au même endroit où la visibilité change (c'est-à-dire que vous ne devriez pas changer myElement.style.displayà de nombreux endroits, à la place, appelez une fonction / méthode qui le fait ceci et tout ce que vous pourriez souhaiter).


8
Mais comment pourriez-vous détecter le changement de visibilité (c'est-à-dire appeler une fonction dès qu'un élément devient visible)?
Anderson Green

Je pense que vous ne pouvez pas faire ça. Ce que vous feriez au lieu d'essayer de détecter le changement, c'est de savoir exactement où il est provoqué et d'y mettre votre appel. Si le changement de visibilité n'est pas quelque chose dont votre propre code est directement responsable (par exemple, une bibliothèque) et que la logique par laquelle cela se produit est très artificielle, je suppose que vous n'avez pas de chance? :)
maltalef

6
J'ai décliné cette question car, malgré tout le sens qu'elle a, elle n'a aucun rapport avec le problème réel. (si je n'en affiche aucun sur un cadre, tous les éléments enfants deviennent invisibles)
Sebas

2
@Sebas, je ne comprends pas vraiment pourquoi la visibilité des enfants compte ici. Quoi qu'il en soit, si la réponse n'était pas utile pour votre cas particulier (quel qu'il soit) mais indique une solution (ou une explication pour laquelle il n'y a pas de solution) pour la plupart des programmeurs, c'est toujours une réponse valable à mon humble avis. Si vous préférez l'une des autres réponses (en particulier celle qui a été faite plus tard, lorsque la technologie s'est améliorée et que de nouvelles options sont devenues disponibles), je pense qu'une demande de changement de la bonne réponse serait plus appropriée qu'un vote défavorable. En tout cas, merci pour le heads-up :)
maltalef

2
@figha, pas les enfants, mais si l'élément que vous regardez est dans un cadre qui est affiché = aucun, vous n'en aurez aucun signe.
Sebas

67

À l'avenir, la nouvelle API HTML Intersection Observer est ce que vous recherchez. Il vous permet de configurer un rappel qui est appelé chaque fois qu'un élément, appelé la cible, croise la fenêtre de l'appareil ou un élément spécifié. Il est disponible dans les dernières versions de Chrome, Firefox et Edge. Voir https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API pour plus d'informations.

Exemple de code simple pour observer l'affichage: aucune commutation:

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

En action: https://jsfiddle.net/elmarj/u35tez5n/5/


2
> L'API Intersection Observer vous permet de configurer un rappel qui est appelé chaque fois qu'un élément, appelé la cible, croise soit la fenêtre de l'appareil, soit un élément spécifié;
Stil

1
Notez qu'InteractionObserver ne fonctionne pas sur Safari pour le moment. caniuse.com/#feat=intersectionobserver Il semble qu'un correctif soit en cours. bugs.webkit.org/show_bug.cgi?id=159475
Pic Mickael

8
Quand le manque de soutien d'IE pour quelque chose de cool comme celui-ci cessera-t-il de ruiner nos vies?
Peter Moore

5
@PeterMoore dès que vous arrêtez d'essayer de le soutenir. Ne le fais pas.
johny why

4
LOL. Parfois, ce n'est pas notre décision.
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 });

Je suis peut-être un peu en retard, mais vous pouvez simplement utiliser le MutationObserver pour observer les changements sur l'élément souhaité. En cas de changement, il vous suffira de vérifier si l'élément est affiché.


4
Cela ne fonctionne pas lorsque le targetNode n'est pas affiché car un ancêtre n'est pas affiché mais est ensuite affiché.
Marco Eckstein

Vote positif! J'ai utilisé ceci dans une autre réponse stackoverflow: stackoverflow.com/questions/48792245/…
Nick Timmer

Malheureusement, cela ne fonctionne que lorsque vous utilisez des styles en ligne sur l'élément, pas lorsque le changement est le résultat d'un changement de classe CSS (ce qui est le scénario le plus probable, étant donné que dans la première situation, vous avez probablement déjà un contrôle programmatique complet). Violon qui montre le problème: jsfiddle.net/elmarj/uye62Lxc/4 . Voir ici pour une discussion plus complète sur la façon d'observer les changements de style: dev.to/oleggromov/observing-style-changes---d4f
Elmar Jansen

En fait, le bon observateur à utiliser ici serait un IntersectionObserver- stackoverflow.com/a/52627221/2803743
kano

Cette solution est utile lorsque vous souhaitez activer et désactiver un élément et que vous n'avez aucun contrôle direct sur cet élément et que vous souhaitez réagir au changement de valeur d'affichage
Eran Goldin

15

Il y a au moins un moyen, mais ce n'est pas très bon. Vous pouvez simplement interroger l'élément pour des changements comme celui-ci:

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

La norme DOM spécifie également les événements de mutation , mais je n'ai jamais eu la chance de les utiliser, et je ne suis pas sûr de leur compatibilité. Vous les utiliseriez comme ceci:

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

Ce code me vient à l'esprit, donc je ne suis pas sûr qu'il fonctionnerait.

La solution la meilleure et la plus simple serait d'avoir un rappel dans la fonction affichant votre cible.


1
Intéressant, merci. Quelques années plus tard, le statut de DOMAttrModified a changé: "Obsolète. Cette fonctionnalité a été supprimée des standards Web. Bien que certains navigateurs puissent encore la prendre en charge, elle est en cours de suppression." (Mozilla)
BurninLeo

MutationObserver est le nouveau nouveau.
mindplay.dk

14

J'ai eu ce même problème et j'ai créé un plugin jQuery pour le résoudre pour notre site.

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

Voici comment vous l'utiliseriez en fonction de votre exemple:

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

4
Cette solution utilise .is(':visible')avec setTimeout.
Hp93

7

Comme le dit @figha, s'il s'agit de votre propre page Web , vous devez simplement exécuter tout ce dont vous avez besoin après avoir rendu l'élément visible.

Cependant, dans le but de répondre à la question (et à quiconque crée des extensions Chrome ou Firefox , où il s'agit d'un cas d'utilisation courant), Mutation Summary et Mutation Observer permettront aux modifications DOM de déclencher des événements.

Par exemple, déclencher un événement pour un élément avec un data-widgetattribut ajouté au DOM. Empruntant cet excellent exemple au blog de 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);

Les réponses comprennent added, removed, valueChangedet plus . valueChangedinclut tous les attributs, y compris displayetc.


Probablement parce qu'il veut savoir quand il est réellement à l'écran. Oui, je ne peux que supposer que le downvoter a la même raison.
Dave Hillier

Ne répond pas à la question et il n'est pas conseillé de publier uniquement des liens.
Alex Holsgrove

@AlexHolsgrove J'ai ajouté un exemple, à partir du lien. Étant donné que l'affiche parle d'ajouter une barre d'outils à la page, il semble qu'ils pourraient ajouter une barre d'outils à une page tierce et attendre qu'un élément soit ajouté au DOM, auquel cas Mutations est la meilleure API.
mikemaccana

Notez que cela ne couvre toujours pas cette partie qui explique où dans le processus d'observation des mutations la «visibilité» entre en jeu.
Mike 'Pomax' Kamermans


3

Juste pour commenter la prise en charge du navigateur d'écouteur d'événements DOMAttrModified:

Prise en charge de plusieurs navigateurs

Ces événements ne sont pas implémentés de manière cohérente dans différents navigateurs, par exemple:

  • IE avant la version 9 ne prenait pas du tout en charge les événements de mutation et n'en implémentait pas certains correctement dans la version 9 (par exemple, DOMNodeInserted)

  • WebKit ne prend pas en charge DOMAttrModified (voir le bogue Webkit 8191 et la solution de contournement)

  • Les "événements de nom de mutation", c'est-à-dire DOMElementNameChanged et DOMAttributeNameChanged ne sont pas pris en charge dans Firefox (à partir de la version 11), et probablement aussi dans d'autres navigateurs.

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


-2

ma solution:

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

par exemple:

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

function processMoreLessButton(){
//some logic
}

5
Vous devriez dire à tout le monde que vous avez utilisé le code original de jQuery, cela inspirerait plus de confiance;)
aemonge

1
"ma solution". Le culot sur ce gars.
André Silva

@ AndréSilva Il a peut-être écrit jQuery. : O
Andrew
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.