Détecter quand la hauteur d'un div change à l'aide de jQuery


141

J'ai un div qui contient du contenu qui est ajouté et supprimé dynamiquement, donc sa hauteur change souvent. J'ai aussi un div qui est absolument positionné directement en dessous avec javascript, donc à moins que je ne puisse détecter quand la hauteur du div change, je ne peux pas repositionner le div en dessous.

Alors, comment puis-je détecter quand la hauteur de cette div change? Je suppose qu'il y a un événement jQuery que je dois utiliser, mais je ne sais pas à quel événement se connecter.


4
Je me demande pourquoi on ne voudrait pas utiliser un plugin lors de l'utilisation de jQuery.
Andre Calil

1
@ user007 Qu'est-ce qui fait que la taille de vos éléments a changé?
A. Wolff

@roasted ma hauteur div change lorsqu'un élément y est ajouté, l'ajout est fait par jquery
user007

1
@ user007 donc lorsque vous ajoutez quelque chose au DIV, vous pouvez déclencher un événement de redimensionnement personnalisé pour le DIV. Une autre façon (pire IMO) pourrait être d'utiliser une méthode personnalisée pour ajouter du contenu qui étend simplement la méthode native jquery append (), utilisez-la avec un rappel, par exemple
A. Wolff

@roasted Merci pour le tuyau.
user007

Réponses:


64

Utilisez un capteur de redimensionnement de la bibliothèque css-element-queries:

https://github.com/marcj/css-element-queries

new ResizeSensor(jQuery('#myElement'), function() {
    console.log('myelement has been resized');
});

Il utilise une approche basée sur les événements et ne fait pas perdre de temps à votre processeur. Fonctionne dans tous les navigateurs, y compris. IE7 +.


5
solution sympa, il utilise un nouvel élément invisible comme superposition sur la cible souhaitée et utilise l'événement "scroll" sur l'overlay pour déclencher des changements.
Eike Thies

2
C'est la seule solution qui fonctionne dans tous les cas, y compris lorsque le contenu et les attributs ne changent pas mais que les dimensions changent (exemple: dimensions en pourcentage à l'aide de css)
FF_Dev

2
La meilleure solution de loin.
dlsso

1
Ce n'est pas la réponse la plus votée ici est une tragédie. Cela fonctionne vraiment à 100%.
Jimbo Jonny

Cela ne semble pas fonctionner pour les éléments qui commencent cachés.
greatwitenorth

48

J'ai écrit un plugin il y a quelque temps pour attrchange listener qui ajoute essentiellement une fonction d'écoute sur le changement d'attribut. Même si je le dis comme un plugin, en fait c'est une simple fonction écrite comme un plugin jQuery .. donc si vous voulez .. supprimez le code spécifique du plugin et utilisez les fonctions de base.

Remarque: ce code n'utilise pas d'interrogation

consultez cette simple démo http://jsfiddle.net/aD49d/

$(function () {
    var prevHeight = $('#test').height();
    $('#test').attrchange({
        callback: function (e) {
            var curHeight = $(this).height();            
            if (prevHeight !== curHeight) {
               $('#logger').text('height changed from ' + prevHeight + ' to ' + curHeight);

                prevHeight = curHeight;
            }            
        }
    }).resizable();
});

Page du plugin: http://meetselva.github.io/attrchange/

Version réduite: (1.68kb)

(function(e){function t(){var e=document.createElement("p");var t=false;if(e.addEventListener)e.addEventListener("DOMAttrModified",function(){t=true},false);else if(e.attachEvent)e.attachEvent("onDOMAttrModified",function(){t=true});else return false;e.setAttribute("id","target");return t}function n(t,n){if(t){var r=this.data("attr-old-value");if(n.attributeName.indexOf("style")>=0){if(!r["style"])r["style"]={};var i=n.attributeName.split(".");n.attributeName=i[0];n.oldValue=r["style"][i[1]];n.newValue=i[1]+":"+this.prop("style")[e.camelCase(i[1])];r["style"][i[1]]=n.newValue}else{n.oldValue=r[n.attributeName];n.newValue=this.attr(n.attributeName);r[n.attributeName]=n.newValue}this.data("attr-old-value",r)}}var r=window.MutationObserver||window.WebKitMutationObserver;e.fn.attrchange=function(i){var s={trackValues:false,callback:e.noop};if(typeof i==="function"){s.callback=i}else{e.extend(s,i)}if(s.trackValues){e(this).each(function(t,n){var r={};for(var i,t=0,s=n.attributes,o=s.length;t<o;t++){i=s.item(t);r[i.nodeName]=i.value}e(this).data("attr-old-value",r)})}if(r){var o={subtree:false,attributes:true,attributeOldValue:s.trackValues};var u=new r(function(t){t.forEach(function(t){var n=t.target;if(s.trackValues){t.newValue=e(n).attr(t.attributeName)}s.callback.call(n,t)})});return this.each(function(){u.observe(this,o)})}else if(t()){return this.on("DOMAttrModified",function(e){if(e.originalEvent)e=e.originalEvent;e.attributeName=e.attrName;e.oldValue=e.prevValue;s.callback.call(this,e)})}else if("onpropertychange"in document.body){return this.on("propertychange",function(t){t.attributeName=window.event.propertyName;n.call(e(this),s.trackValues,t);s.callback.call(this,t)})}return this}})(jQuery)

25
Cela résout le problème si vous redimensionnez le div manuellement, cela ne résout pas la question d'origine non? Si vous ajoutez du contenu dynamiquement, il ne détecte pas le changement de hauteur: jsfiddle.net/aD49d/25
smets.kevin

Je serais également intéressé de savoir s'il y avait un moyen de faire fonctionner ce contenu pour un contenu dynamique.
EricP

4
@JoeCoder Ce code attrchange repose sur les événements DOM déclenchés par le navigateur lorsqu'il y a une action de l'utilisateur. Cependant, le contenu dynamique de cet exemple est inclus par programme, ce qui ne déclenche malheureusement aucun événement. "Polling" semble être une autre option plus simple ici .. une autre option pourrait se déclencher manuellement une fois le contenu dynamique inclus.
Selvakumar Arumugam

28

Vous pouvez utiliser l'événement DOMSubtreeModified

$(something).bind('DOMSubtreeModified' ...

Mais cela se déclenchera même si les dimensions ne changent pas, et la réaffectation de la position chaque fois qu'elle se déclenche peut nuire aux performances. D'après mon expérience en utilisant cette méthode, vérifier si les dimensions ont changé est moins cher et vous pouvez donc envisager de combiner les deux.

Ou si vous modifiez directement le div (plutôt que le div soit modifié par l'entrée de l'utilisateur de manière imprévisible, comme s'il est contentEditable), vous pouvez simplement déclencher un événement personnalisé chaque fois que vous le faites.

Inconvénient: IE et Opera ne mettent pas en œuvre cet événement.


12
IE et Opera ne mettent pas en œuvre cet événement: quirksmode.org/dom/events/index.html
DEfusion

14
DomSubtreeModified a été déprécié
Adonis K.Kakoulidis

2
La façon moderne de faire cela serait d'utiliser un MutationObserver: developer.mozilla.org/en-US/docs/Web/API/MutationObserver
Christian Bankester

21

Voici comment j'ai récemment géré ce problème:

$('#your-resizing-div').bind('getheight', function() {
    $('#your-resizing-div').height();
});

function your_function_to_load_content() {
    /*whatever your thing does*/
    $('#your-resizing-div').trigger('getheight');
}

Je sais que j'ai quelques années de retard à la fête, je pense juste que ma réponse peut aider certaines personnes à l'avenir, sans avoir à télécharger de plugins.


1
Je suppose que d'une certaine manière ce n'est pas la meilleure façon de le faire, mais j'aime bien ça, car cela signifie que vous pouvez le déclencher comme un rappel à la fin d'une animation. Le plugin de redimensionnement continuera à se déclencher tout au long d'une animation, ce qui pourrait être utile, mais pourrait également causer des problèmes. Cette méthode vous permet au moins de contrôler le moment de déclencher le test de hauteur.
andyface

Que fait exactement votre code? Pourquoi ne pouvons-nous pas simplement utiliser le code que vous écrivez à l'intérieur de l'événement de liaison dans la fonction insted de liaison et de déclenchement?
user1447420

Mais ce n'est pas automatique, n'est-ce pas?
Albert Català

17

Vous pouvez utiliser la MutationObserverclasse.

MutationObserverfournit aux développeurs un moyen de réagir aux changements dans un DOM. Il est conçu pour remplacer les événements de mutation définis dans la spécification des événements DOM3.

Exemple ( source )

// select the target node
var target = document.querySelector('#some-id');

// create an observer instance
var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    console.log(mutation.type);
  });    
});

// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };

// pass in the target node, as well as the observer options
observer.observe(target, config);

// later, you can stop observing
observer.disconnect();

C'est la bonne réponse. Jetez également un œil à MutationSummary, une bibliothèque qui s'appuie sur MutationObservers: github.com/rafaelw/mutation-summary
Christian Bankester

9

Il existe un plugin jQuery qui peut très bien gérer cela

http://www.jqui.net/jquery-projects/jquery-mutate-official/

voici une démonstration de celui-ci avec différents scénarios quant au changement de hauteur, si vous redimensionnez le div bordé de rouge.

http://www.jqui.net/demo/mutate/


C'est beau, mais n'est-il pas par défaut interroger l'interface utilisateur toutes les millisecondes pour les changements? Est-ce efficace?
Michael Scott Cuthbert

1
@MichaelScottCuthbert Cela a été écrit il y a longtemps, mais je l'ai utilisé setTimeout, donc ça prendrait 1ms + [temps qu'il faut pour faire les vérifications] en bref, mais l'idée était d'écouter constamment, une fois que vous l'avez fait, déclencher à nouveau, c'est comme une queue. Je suis sûr que je pourrais le faire beaucoup mieux mais pas beaucoup de temps.
Val

Ah, oui, je vois que vous étiez environ un an avant la solution de Vega (que j'ai finalement utilisée) et avant que tous les auditeurs DOMSubtreeModified, etc. soient largement supportés. J'ai cependant beaucoup appris en lisant votre code, donc je pense que cela vaut la peine de maintenir les liens.
Michael Scott Cuthbert

7

En réponse à user007:

Si la hauteur de votre élément change en raison d'éléments qui y sont ajoutés à l'aide de .append() vous ne devriez pas avoir besoin de détecter le changement de hauteur. Ajoutez simplement le repositionnement de votre deuxième élément dans la même fonction où vous ajoutez le nouveau contenu à votre premier élément.

Un péché:

Exemple de travail

$('.class1').click(function () {
    $('.class1').append("<div class='newClass'><h1>This is some content</h1></div>");
    $('.class2').css('top', $('.class1').offset().top + $('.class1').outerHeight());
});

2

Vous pouvez créer un setInterval simple.

function someJsClass()
{
  var _resizeInterval = null;
  var _lastHeight = 0;
  var _lastWidth = 0;
  
  this.Initialize = function(){
    var _resizeInterval = setInterval(_resizeIntervalTick, 200);
  };
  
  this.Stop = function(){
    if(_resizeInterval != null)
      clearInterval(_resizeInterval);
  };
  
  var _resizeIntervalTick = function () {
    if ($(yourDiv).width() != _lastWidth || $(yourDiv).height() != _lastHeight) {
      _lastWidth = $(contentBox).width();
      _lastHeight = $(contentBox).height();
      DoWhatYouWantWhenTheSizeChange();
    }
  };
}

var class = new someJsClass();
class.Initialize();

ÉDITER:

Ceci est un exemple avec une classe. Mais vous pouvez faire quelque chose de plus simple.


0

Vous pouvez l'utiliser, mais il ne prend en charge que Firefox et Chrome.

$(element).bind('DOMSubtreeModified', function () {
  var $this = this;
  var updateHeight = function () {
    var Height = $($this).height();
    console.log(Height);
  };
  setTimeout(updateHeight, 2000);
});


0

Assez basique mais fonctionne:

function dynamicHeight() {
    var height = jQuery('').height();
    jQuery('.edito-wrapper').css('height', editoHeight);
}
editoHeightSize();

jQuery(window).resize(function () {
    editoHeightSize();
});

cela ne sera déclenché que si la fenêtre est redimensionnée, mais OP veut lier un événement de redimensionnement à un conteneur spécifique
Fanie Void
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.