Detecting when a div's height changes using jQ

2019-01-01 01:54发布

问题:

I\'ve got a div that contains some content that\'s being added and removed dynamically, so its height is changing often. I also have a div that is absolutely positioned directly underneath with javascript, so unless I can detect when the height of the div changes, I can\'t reposition the div below it.

So, how can I detect when the height of that div changes? I assume there\'s some jQuery event I need to use, but I\'m not sure which one to hook into.

回答1:

Use a resize sensor from the css-element-queries library:

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

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

It uses a event based approach and doesn\'t waste your cpu time. Works in all browsers incl. IE7+.



回答2:

I wrote a plugin sometime back for attrchange listener which basically adds a listener function on attribute change. Even though I say it as a plugin, actually it is a simple function written as a jQuery plugin.. so if you want.. strip off the plugin specfic code and use the core functions.

Note: This code doesn\'t use polling

check out this simple 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 page: http://meetselva.github.io/attrchange/

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


回答3:

You can use the DOMSubtreeModified event

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

But this will fire even if the dimensions don\'t change, and reassigning the position whenever it fires can take a performance hit. In my experience using this method, checking whether the dimensions have changed is less expensive and so you might consider combining the two.

Or if you are directly altering the div (rather than the div being altered by user input in unpredictable ways, like if it is contentEditable), you can simply fire a custom event whenever you do so.

Downside: IE and Opera don\'t implement this event.



回答4:

This is how I recently handled this 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\');
}

I know I\'m a few years late to the party, just think my answer may help some people in the future, without having to download any plugins.



回答5:

You can use MutationObserver class.

MutationObserver provides developers a way to react to changes in a DOM. It is designed as a replacement for Mutation Events defined in the DOM3 Events specification.

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


回答6:

There is a jQuery plugin that can deal with this very well

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

here is a demo of it with different scenarios as to when the height change, if you resize the red bordered div.

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



回答7:

In response to user007:

If the height of your element is changing due to items being appended to it using .append() you shouldn\'t need to detect the change in height. Simply add the reposition of your second element in the same function where you are appending the new content to your first element.

As in:

Working Example

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


回答8:

You can make a simple setInterval.

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

EDIT:

This is a example with a class. But you can do something easiest.



回答9:

You can use this, but it only supports Firefox and Chrome.

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



回答10:

Pretty basic but works:

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

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