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.

Bob Somers
la source
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 +.

Marc J. Schmidt
la source
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)
Selvakumar Arumugam
la source
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.

paupière
la source
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.

Kyle
la source
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();
EFernandes
la source
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/

Val
la source
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());
});
paul
la source
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.

Estefano Salazar
la source
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);
});

Ronald Rivera
la source
0

Assez basique mais fonctionne:

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

jQuery(window).resize(function () {
    editoHeightSize();
});
Zac
la source
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