Erkennen, wann sich die Höhe eines Div mit jQuery ändert


141

Ich habe ein Div, das einige Inhalte enthält, die dynamisch hinzugefügt und entfernt werden, sodass sich seine Höhe häufig ändert. Ich habe auch ein Div, das mit Javascript absolut direkt darunter positioniert ist. Wenn ich also nicht erkennen kann, wann sich die Höhe des Div ändert, kann ich das Div darunter nicht neu positionieren.

Wie kann ich also erkennen, wann sich die Höhe dieses Div ändert? Ich gehe davon aus, dass ich ein jQuery-Ereignis verwenden muss, bin mir aber nicht sicher, in welches ich mich einbinden soll.


4
Ich frage mich, warum man bei der Verwendung von jQuery kein Plugin verwenden möchte.
Andre Calil

1
@ user007 Wodurch ändert sich die Größe Ihrer Elemente?
A. Wolff

@ geröstet meine Div Höhe ändert sich, wenn ein Element daran angehängt wird. Das Anhängen erfolgt durch jquery
user007

1
@ user007 Wenn Sie also etwas an den DIV anhängen, können Sie ein benutzerdefiniertes Größenänderungsereignis für den DIV auslösen. Eine andere Möglichkeit (schlechteste IMO) könnte darin bestehen, eine benutzerdefinierte Methode zum Anhängen von Inhalten zu verwenden, die einfach die native jquery append () -Methode erweitert, und sie mit einem Rückruf zu verwenden, z. B.
A. Wolff,

@ geröstet Danke für den Tipp.
user007

Antworten:


64

Verwenden Sie einen Größenänderungssensor aus der CSS-Element-Abfrage-Bibliothek:

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

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

Es verwendet einen ereignisbasierten Ansatz und verschwendet keine CPU-Zeit. Funktioniert in allen Browsern inkl. IE7 +.


5
Gute Lösung, es verwendet ein unsichtbares neues Element als Überlagerung für das gewünschte Ziel und verwendet das "Bildlauf" -Ereignis für die Überlagerung, um Änderungen auszulösen.
Eike Thies

2
Dies ist die einzige Lösung, die in allen Fällen funktioniert, auch wenn sich Inhalt und Attribute nicht ändern, aber die Dimensionen ändern (Beispiel: prozentuale Dimensionen mit CSS)
FF_Dev

2
Mit Abstand beste Lösung.
dlsso

1
Es ist eine Tragödie, dass dies hier nicht die am häufigsten gewählte Antwort ist. Das funktioniert wirklich zu 100%.
Jimbo Jonny

Dies scheint nicht für Elemente zu funktionieren, die versteckt beginnen.
Greatwitenorth

48

Ich habe vor einiger Zeit ein Plugin für den attrchange- Listener geschrieben, das im Grunde eine Listener-Funktion zur Attributänderung hinzufügt. Obwohl ich es als Plugin sage, ist es tatsächlich eine einfache Funktion, die als jQuery-Plugin geschrieben wurde. Wenn Sie möchten, entfernen Sie den spezifischen Code des Plugins und verwenden Sie die Kernfunktionen.

Hinweis: Dieser Code verwendet keine Abfrage

Schauen Sie sich diese einfache Demo an 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();
});

Plugin-Seite: http://meetselva.github.io/attrchange/

Minimierte Version: (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
Dies löst das Problem, wenn Sie die Größe des Div manuell ändern. Dies löst nicht die ursprüngliche Frage, nein? Wenn Sie Inhalte dynamisch hinzufügen, wird die Höhenänderung nicht erkannt
smets.kevin

Mich würde auch interessieren, ob es eine Möglichkeit gibt, diese Arbeit für dynamische Inhalte zu machen.
EricP

4
@JoeCoder Dieser attrchange-Code basiert auf DOM-Ereignissen, die vom Browser ausgelöst werden, wenn eine Benutzeraktion vorliegt. Dynamische Inhalte in diesem Beispiel sind jedoch programmgesteuert enthalten, was leider keine Ereignisse auslöst. "Polling" scheint hier eine weitere einfachere Option zu sein. Eine andere Option kann manuell ausgelöst werden, nachdem der dynamische Inhalt enthalten ist.
Selvakumar Arumugam

28

Sie können das Ereignis DOMSubtreeModified verwenden

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

Dies wird jedoch auch dann ausgelöst, wenn sich die Abmessungen nicht ändern. Wenn Sie die Position bei jedem Brand neu zuweisen, kann dies zu Leistungseinbußen führen. Nach meiner Erfahrung mit dieser Methode ist die Überprüfung, ob sich die Abmessungen geändert haben, kostengünstiger. Daher sollten Sie möglicherweise eine Kombination aus beiden in Betracht ziehen.

Oder wenn Sie das Div direkt ändern (anstatt das Div durch Benutzereingaben auf unvorhersehbare Weise zu ändern, z. B. wenn es contentEditable ist), können Sie jederzeit ein benutzerdefiniertes Ereignis auslösen.

Nachteil: IE und Opera implementieren dieses Ereignis nicht.


12
IE & Opera implementieren dieses Ereignis nicht: quirksmode.org/dom/events/index.html
DEfusion

14
DomSubtreeModified wurde beraubt
Adonis K. Kakoulidis

2
Der moderne Weg, dies zu tun, wäre die Verwendung eines MutationObservers: developer.mozilla.org/en-US/docs/Web/API/MutationObserver
Christian Bankester

21

So habe ich kürzlich dieses Problem behandelt:

$('#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');
}

Ich weiß, dass ich ein paar Jahre zu spät zur Party komme. Ich denke nur, meine Antwort könnte einigen Leuten in Zukunft helfen, ohne dass ich Plugins herunterladen muss.


1
Ich denke, in gewisser Hinsicht ist dies nicht der beste Weg, aber ich mag es wirklich sehr, da es bedeutet, dass Sie es am Ende einer Animation als Rückruf auslösen können. Das Größenänderungs-Plugin wird während einer Animation weiter ausgelöst, was hilfreich sein kann, aber auch Probleme verursachen kann. Mit dieser Methode können Sie zumindest steuern, wann die Höhenprüfung ausgelöst werden soll.
Andyface

Was genau macht Ihr Code? Warum können wir den Code, den Sie in das Bindeereignis schreiben, nicht einfach in der Funktion zum Binden und Auslösen verwenden?
user1447420

Aber das ist nicht automatisch, nicht wahr?
Albert Català

16

Sie können MutationObserverKlasse verwenden.

MutationObserverbietet Entwicklern die Möglichkeit, auf Änderungen in einem DOM zu reagieren. Es ist als Ersatz für Mutationsereignisse konzipiert, die in der DOM3-Ereignisspezifikation definiert sind.

Beispiel ( Quelle )

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

Dies ist die richtige Antwort. Schauen Sie sich auch MutationSummary an, eine Bibliothek, die auf MutationObservers aufbaut: github.com/rafaelw/mutation-summary
Christian Bankester

9

Es gibt ein jQuery-Plugin, das sehr gut damit umgehen kann

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

Hier ist eine Demo davon mit verschiedenen Szenarien, wann sich die Höhe ändert, wenn Sie die Größe des rot umrandeten Div ändern.

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


Es ist wunderschön, aber fragt es nicht standardmäßig jede Millisekunde die Benutzeroberfläche nach Änderungen ab? Ist das effizient?
Michael Scott Cuthbert

1
@MichaelScottCuthbert Es wurde vor langer Zeit geschrieben, aber ich habe es verwendet setTimeout, also wäre es kurz 1 ms + [Zeit, die benötigt wird, um die Überprüfungen durchzuführen], aber die Idee war, ständig zuzuhören, sobald Sie es erneut ausgelöst haben, ist es so eine Schlange. Ich bin sicher, ich könnte es viel besser machen, aber nicht viel Zeit.
Val

Ah, ja, ich sehe, dass Sie ungefähr ein Jahr vor Vegas Lösung (die ich letztendlich verwendet habe) und bevor alle DOMSubtreeModified usw.-Hörer weitgehend unterstützt wurden. Ich habe eine Menge durch das Lesen Ihres Codes gelernt, daher denke ich, dass es sich lohnt, die Links aufrechtzuerhalten.
Michael Scott Cuthbert

7

Als Antwort auf user007:

Wenn sich die Höhe Ihres Elements ändert, weil Elemente mit an das Element angehängt werden .append() , sollten Sie die Höhenänderung nicht erkennen müssen. Fügen Sie einfach die Neupositionierung Ihres zweiten Elements in derselben Funktion hinzu, in der Sie den neuen Inhalt an Ihr erstes Element anhängen.

Wie in:

Arbeitsbeispiel

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

2

Sie können ein einfaches setInterval erstellen.

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

BEARBEITEN:

Dies ist ein Beispiel für eine Klasse. Aber Sie können etwas am einfachsten tun.


0

Sie können dies verwenden, es werden jedoch nur Firefox und Chrome unterstützt.

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


0

Ziemlich einfach, funktioniert aber:

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

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

Dies wird nur ausgelöst, wenn die Fenstergröße geändert wird, aber OP möchte ein Größenänderungsereignis an einen bestimmten Container binden
Fanie Void
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.