javascript - Upptäcka när en div:s höjd ändras med jQuery


Jag har en div som innehåller något innehåll som läggs till och tas bort dynamiskt, så dess höjd ändras ofta. Jag har också en div som är absolut positionerad direkt under med JavaScript, så om jag inte kan upptäcka när divens höjd ändras, kan jag inte omplacera div:en under den.

Så, hur kan jag upptäcka när höjden på den där div:en ändras? Jag antar att det finns någon jQuery-händelse jag behöver använda, men jag är inte säker på vilken jag ska koppla in.

Svar #1

Använd en storleksändringssensor från css-element-queries-biblioteket:

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

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

Den använder en händelsebaserad metod och slösar inte med din CPU-tid. Fungerar i alla webbläsare inklusive IE7+.

Svar #2

Jag skrev ett plugin för ett tag sedan för attrchange-lyssnaren som i princip lägger till en lyssnarfunktion vid attributförändring. Även om jag säger att det är ett plugin, är det egentligen en enkel funktion skriven som ett jQuery-plugin.. så om du vill.. ta bort plugin-specifik kod och använd kärnfunktionerna.

Observera: Denna kod använder inte polling

kolla in denna enkla demo 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-sida: http://meetselva.github.io/attrchange/

Minimerad version: (1,68 kb)

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

Svar #3

Du kan använda DOMSubtreeModified-händelsen

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

Men detta kommer att utlösas även om dimensionerna inte ändras, och att tilldela positionen på nytt varje gång det utlöses kan påverka prestandan. Enligt min erfarenhet med att använda denna metod är det mindre kostsamt att kontrollera om dimensionerna har ändrats, så du kan överväga att kombinera de två.

Eller om du direkt ändrar div:en (istället för att div:en ändras av användarinmatning på oförutsägbara sätt, som om den är contentEditable), kan du helt enkelt utlösa ett anpassat evenemang när du gör det.

Nackdel: IE och Opera implementerar inte denna händelse.

Svar #4

Så här hanterade jag nyligen detta problem:

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

Jag vet att jag är några år sen till festen, tänk bara att mitt svar kan hjälpa några människor i framtiden, utan att behöva ladda ner några tillägg.

Svar #5

Du kan använda MutationObserver-klassen.

MutationObserver ger utvecklare ett sätt att reagera på förändringar i en DOM. Det är designat som en ersättning för Mutation Events som definieras i DOM3 Events-specifikationen.

Exempel (källa)

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

Relaterade artiklar