jQuery événement pour déclencher l'action quand une div est rendue visible

j'utilise jQuery sur mon site et j'aimerais déclencher certaines actions quand une certaine div est rendue visible.

est-il possible d'attacher une sorte de gestionnaire d'événements "isvisible" à des divs arbitraires et de faire exécuter un certain code lorsque le div est rendu visible?

j'aimerais quelque chose comme le pseudo suivant:

$(function() {
  $('#contentDiv').isvisible(function() {
    alert("do something");
  });
});

le code d'alerte ("faire quelque chose") ne doit pas s'allumer tant que le contenu n'est pas rendue visible.

Merci.

275
demandé sur frankadelic 2009-08-04 03:24:48

21 réponses

, Vous pouvez toujours ajouter à l'original .afficher () la méthode pour ne pas avoir à déclencher d'événements à chaque fois que vous montrez quelque chose ou si vous en avez besoin pour travailler avec le code d'héritage:

jQuery extension:

jQuery(function($) {

  var _oldShow = $.fn.show;

  $.fn.show = function(speed, oldCallback) {
    return $(this).each(function() {
      var obj         = $(this),
          newCallback = function() {
            if ($.isFunction(oldCallback)) {
              oldCallback.apply(obj);
            }
            obj.trigger('afterShow');
          };

      // you can trigger a before show if you want
      obj.trigger('beforeShow');

      // now use the old function to show the element passing the new callback
      _oldShow.apply(obj, [speed, newCallback]);
    });
  }
});

exemple d'utilisation:

jQuery(function($) {
  $('#test')
    .bind('beforeShow', function() {
      alert('beforeShow');
    }) 
    .bind('afterShow', function() {
      alert('afterShow');
    })
    .show(1000, function() {
      alert('in show callback');
    })
    .show();
});

cela vous permet effectivement de faire quelque chose avant et après-coup tout en exécutant le comportement normal de l'original .méthode show ().

vous pouvez aussi créer une autre méthode pour ne pas avoir à surcharger l'original .méthode show ().

176
répondu Tres 2013-05-09 12:22:48

il n'y a pas d'événement natif dans lequel vous pouvez vous connecter pour cela, cependant vous pouvez déclencher un événement à partir de votre script après avoir rendu le div visible en utilisant le . déclencheur fonction

E. g

//declare event to run when div is visible
function isVisible(){
   //do something

}

//hookup the event
$('#someDivId').bind('isVisible', isVisible);

//show div and trigger custom event in callback when div is visible
$('#someDivId').show('slow', function(){
    $(this).trigger('isVisible');
});
71
répondu redsquare 2009-08-03 23:39:00

Le problème est pris en charge par DOM mutation observateurs . Ils vous permettent de lier un observateur (une fonction) à des événements de changement de contenu, de texte ou d'attributs d'éléments dom.

avec la sortie de IE11, tous les principaux navigateurs supportent cette fonctionnalité, cochez http://caniuse.com/mutationobserver

le code de l'exemple est le suivant:

$(function() {
  $('#show').click(function() {
    $('#testdiv').show();
  });

  var observer = new MutationObserver(function(mutations) {
    alert('Attributes changed!');
  });
  var target = document.querySelector('#testdiv');
  observer.observe(target, {
    attributes: true
  });

});
<div id="testdiv" style="display:none;">hidden</div>
<button id="show">Show hidden div</button>

<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
67
répondu hegemon 2016-12-03 21:37:35

vous pouvez utiliser jQuery LIVE Query plugin . Et écrire le code comme suit:

$('#contentDiv:visible').livequery(function() {
    alert("do something");
});

alors chaque fois que le contentDiv est visible, "faire quelque chose" sera alerté!

24
répondu ax003d 2018-07-26 15:47:58

la solution de redsquare est la bonne réponse.

mais en tant que solution théorique vous pouvez écrire une fonction qui sélectionne les éléments Classés par .visibilityCheck ( pas tous les éléments visibles ) et vérifier leur valeur de propriété visibility ; si true alors faire quelque chose.

par la suite, la fonction doit être exécutée périodiquement en utilisant le setInterval() fonction. Vous pouvez arrêter le minuteur en utilisant le clearInterval() lors d'un appel réussi.

voici un exemple:

function foo() {
    $('.visibilityCheck').each(function() {
        if ($(this).is(':visible')){
            // do something
        }
    });
}

window.setInterval(foo, 100);

vous pouvez également effectuer quelques améliorations de performance sur elle, cependant, la solution est fondamentalement absurde à utiliser dans l'action. Si...

20
répondu sepehr 2018-01-26 04:46:33

le code suivant (tiré de http://maximeparmentier.com/2012/11/06/bind-show-hide-events-with-jquery / ) vous permettra d'utiliser $('#someDiv').on('show', someFunc); .

(function ($) {
  $.each(['show', 'hide'], function (i, ev) {
    var el = $.fn[ev];
    $.fn[ev] = function () {
      this.trigger(ev);
      return el.apply(this, arguments);
    };
  });
})(jQuery);
10
répondu JellicleCat 2014-01-20 16:27:46

Si vous voulez déclencher l'événement sur tous les éléments (et les éléments enfants) qui sont réellement visibles, par $.montrer, à bascule, toggleClass, addClass, ou removeClass:

$.each(["show", "toggle", "toggleClass", "addClass", "removeClass"], function(){
    var _oldFn = $.fn[this];
    $.fn[this] = function(){
        var hidden = this.find(":hidden").add(this.filter(":hidden"));
        var result = _oldFn.apply(this, arguments);
        hidden.filter(":visible").each(function(){
            $(this).triggerHandler("show"); //No bubbling
        });
        return result;
    }
});

et maintenant votre élément:

$("#myLazyUl").bind("show", function(){
    alert(this);
});

vous pouvez ajouter des overrides à des fonctions jQuery supplémentaires en les ajoutant au tableau en haut (comme "attr")

9
répondu Glenn Lane 2011-09-30 18:25:24

masquer/afficher l'événement déclencheur basé sur Glenns ideea: supprimé bascule parce qu'il allume show / hide et nous ne voulons pas 2 feux pour un événement

$(function(){
    $.each(["show","hide", "toggleClass", "addClass", "removeClass"], function(){
        var _oldFn = $.fn[this];
        $.fn[this] = function(){
            var hidden = this.find(":hidden").add(this.filter(":hidden"));
            var visible = this.find(":visible").add(this.filter(":visible"));
            var result = _oldFn.apply(this, arguments);
            hidden.filter(":visible").each(function(){
                $(this).triggerHandler("show");
            });
            visible.filter(":hidden").each(function(){
                $(this).triggerHandler("hide");
            });
            return result;
        }
    });
});
9
répondu catalint 2012-01-17 17:05:49

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 basé sur votre exemple:

$('#contentDiv').visibilityChanged(function(element, visible) {
    alert("do something");
});
5
répondu Shaun Bowe 2015-04-28 18:54:02

utiliser jQuery Waypoints:

$('#contentDiv').waypoint(function() {
   alert('do something');
});

autres exemples sur le site de jQuery Waypoints .

4
répondu Fedir RYKHTIK 2013-08-27 09:19:26

vous pouvez également essayer jQuery appear plugin comme mentionné dans le fil parallèle https://stackoverflow.com/a/3535028/741782

2
répondu antongorodezkiy 2017-05-23 11:55:10

ce support facilite et déclenche l'événement après l'animation fait! [testé sur jQuery 2.2.4]

(function ($) {
    $.each(['show', 'hide', 'fadeOut', 'fadeIn'], function (i, ev) {
        var el = $.fn[ev];
        $.fn[ev] = function () {
            var result = el.apply(this, arguments);
            var _self=this;
            result.promise().done(function () {
                _self.triggerHandler(ev, [result]);
                //console.log(_self);
            });
            return result;
        };
    });
})(jQuery);

inspiré de http://viralpatel.net/blogs/jquery-trigger-custom-event-show-hide-element /

2
répondu MSS 2017-01-07 08:27:43

il y a un plugin jQuery disponible pour regarder le changement dans les attributs de DOM,

https://github.com/darcyclarke/jQuery-Watch-Plugin

le plugin enveloppe tout ce que vous devez faire est de lier MutationObserver

vous pouvez alors l'utiliser pour regarder le div en utilisant:

$("#selector").watch('css', function() {
    console.log("Visibility: " + this.style.display == 'none'?'hidden':'shown'));
    //or any random events
});
1
répondu tlogbon 2014-01-20 19:04:49

ce qui m'a aidé ici est récent ResizeObserver spec polyfill :

const divEl = $('#section60');

const ro = new ResizeObserver(() => {
    if (divEl.is(':visible')) {
        console.log("it's visible now!");
    }
});
ro.observe(divEl[0]);

notez que c'est crossbrowser et performant (pas de sondage).

1
répondu Artem Vasiliev 2017-08-11 16:28:52

j'ai fait une simple fonction setinterval pour y parvenir. Si l'élément avec la classe div1 est visible, il définit div2 pour être visible. Je ne connais pas de bonne méthode, mais une solution simple.

setInterval(function(){
  if($('.div1').is(':visible')){
    $('.div2').show();
  }
  else {
    $('.div2').hide();
  }      
}, 100);
1
répondu Adi.P 2018-04-24 16:22:04

j'ai changé le déclencheur d'événement hide/show de Catalint basé sur L'idée de Glenns. Mon problème est que j'ai une application modulaire. Je change entre les modules montrant et cacher les divs parents. Puis quand je cache un module et en montre un autre, avec sa méthode j'ai un retard visible quand je change entre les modules. J'ai seulement besoin parfois d'éclairer cet événement, et dans certains enfants spéciaux. J'ai donc décidé de ne notifier que les childs avec la classe "displayObserver "

$.each(["show", "hide", "toggleClass", "addClass", "removeClass"], function () {
    var _oldFn = $.fn[this];
    $.fn[this] = function () {
        var hidden = this.find(".displayObserver:hidden").add(this.filter(":hidden"));
        var visible = this.find(".displayObserver:visible").add(this.filter(":visible"));
        var result = _oldFn.apply(this, arguments);
        hidden.filter(":visible").each(function () {
            $(this).triggerHandler("show");
        }); 
        visible.filter(":hidden").each(function () {
            $(this).triggerHandler("hide");
        });
        return result;
    }
});

Puis, quand un enfant veut écouter pour "montrer" ou "masquer" événement, j'ai ajouté la catégorie "displayObserver", et quand Il ne veut pas continuer à l'écouter, j'ai supprimer la classe

bindDisplayEvent: function () {
   $("#child1").addClass("displayObserver");
   $("#child1").off("show", this.onParentShow);
   $("#child1").on("show", this.onParentShow);
},

bindDisplayEvent: function () {
   $("#child1").removeClass("displayObserver");
   $("#child1").off("show", this.onParentShow);
},

je veux aider

0
répondu ccsakuweb 2013-07-12 10:15:41

Une façon de le faire.

Fonctionne seulement sur les changements de visibilité qui sont faits par changement de classe css, mais peut être étendu pour surveiller les changements d'attribut aussi.

var observer = new MutationObserver(function(mutations) {
        var clone = $(mutations[0].target).clone();
        clone.removeClass();
                for(var i = 0; i < mutations.length; i++){
                    clone.addClass(mutations[i].oldValue);
        }
        $(document.body).append(clone);
        var cloneVisibility = $(clone).is(":visible");
        $(clone).remove();
        if (cloneVisibility != $(mutations[0].target).is(":visible")){
            var visibilityChangedEvent = document.createEvent('Event');
            visibilityChangedEvent.initEvent('visibilityChanged', true, true);
            mutations[0].target.dispatchEvent(visibilityChangedEvent);
        }
});

var targets = $('.ui-collapsible-content');
$.each(targets, function(i,target){
        target.addEventListener('visibilityChanged',VisbilityChanedEventHandler});
        target.addEventListener('DOMNodeRemovedFromDocument',VisbilityChanedEventHandler });
        observer.observe(target, { attributes: true, attributeFilter : ['class'], childList: false, attributeOldValue: true });
    });

function VisbilityChanedEventHandler(e){console.log('Kaboom babe'); console.log(e.target); }
0
répondu Matas Vaitkevicius 2014-03-28 11:11:41

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

exemple d'usage:

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

function processMoreLessButton(){
//some logic
}
0
répondu user2699000 2015-10-20 12:54:27
$( window ).scroll(function(e,i) {
    win_top = $( window ).scrollTop();
    win_bottom = $( window ).height() + win_top;
    //console.log( win_top,win_bottom );
    $('.onvisible').each(function()
    {
        t = $(this).offset().top;
        b = t + $(this).height();
        if( t > win_top && b < win_bottom )
            alert("do something");
    });
});
0
répondu Saifullah khan 2016-12-28 11:37:00

J'espère que cela fera le travail de la manière la plus simple:

$("#myID").on('show').trigger('displayShow');

$('#myID').off('displayShow').on('displayShow', function(e) {
    console.log('This event will be triggered when myID will be visible');
});
0
répondu Prashant Anand Verma 2017-03-09 07:18:19
<div id="welcometo">Özhan</div>
<input type="button" name="ooo" 
       onclick="JavaScript:
                    if(document.all.welcometo.style.display=='none') {
                        document.all.welcometo.style.display='';
                    } else {
                        document.all.welcometo.style.display='none';
                    }">

CE code Auto control non requis query visible ou unvisible control

-3
répondu alpc 2015-12-03 13:50:15