使用jQuery检测div的高度何时更改


141

我有一个div,其中包含一些要动态添加和删除的内容,因此其高度经常变化。我也有一个绝对位于javascript正下方的div,因此,除非我能检测到div的高度何时发生变化,否则无法将div重新定位在其下面。

那么,如何检测该div的高度何时变化?我假设有一些jQuery事件需要使用,但是我不确定要挂入哪个事件。


4
我不知道为什么在使用jQuery时不想使用插件。
Andre Calil

1
@ user007是什么让您的元素大小更改?
A. Wolff

@roasted我的div高度变化,当附加了某些项目时,追加由jquery
user007 2013年

1
@ user007,因此当您向DIV附加内容时,可以触发DIV的自定义调整大小事件。另一种方法(最糟糕的IMO)可能是使用自定义方法来附加内容,该方法只是扩展了本机jquery append()方法,并与回调一起使用,例如
A. Wolff

@roasted感谢您的提示。
2013年

Answers:


64

使用css-element-queries库中的调整大小传感器:

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

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

它使用基于事件的方法,并且不会浪费您的CPU时间。适用于所有浏览器,包括 IE7 +。


5
不错的解决方案,它使用不可见的新元素作为所需目标上的覆盖,并利用覆盖上的“滚动”事件来触发更改。
Eike Thies

2
这是在所有情况下都适用的唯一解决方案,包括当内容和属性没有更改但尺寸更改时(例如:使用CSS的百分比尺寸)
FF_Dev 2015年

2
迄今为止最好的解决方案。
dlsso

1
这不是此处的最高票数答案,这是悲剧。这确实有效100%。
Jimbo Jonny

对于开始隐藏的元素,这似乎不起作用。
greatwitenorth

48

我有时为attrchange监听器写了一个插件,它基本上在属性更改时添加了一个监听器功能。即使我说它是一个插件,但实际上它是一个写为jQuery插件的简单函数。因此,如果需要的话,请剥离插件特定的代码并使用核心函数。

注意:此代码不使用轮询

看看这个简单的演示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();
});

插件页面: http : //meetselva.github.io/attrchange/

缩小版:(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
如果您手动调整div的大小,则可以解决此问题,这不能解决原始问题吗?如果动态添加内容,它不会检测到高度变化:jsfiddle.net/aD49d/25
smets.kevin 2013年

我也想知道是否有一种方法可以使此内容适用于动态内容。
EricP

4
@JoeCoder此attrchange代码依赖于在发生用户操作时由浏览器触发的DOM事件。但是,该示例中的动态内容以编程方式包含在内,但不幸的是,该内容不会触发任何事件。此处的“轮询”似乎是另一个更简单的选项。在包含动态内容之后,其他选项将能够手动触发。
Selvakumar Arumugam 2013年

28

您可以使用DOMSubtreeModified事件

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

但是,即使尺寸不变,也会触发,并且每次触发时重新分配位置都会对性能造成影响。以我使用此方法的经验,检查尺寸是否已更改的成本较低,因此您可以考虑将两者结合起来。

或者,如果您直接更改div(而不是由用户输入以不可预测的方式更改div,例如,如果它是contentEditable),则可以在任何时候简单地触发自定义事件。

缺点:IE和Opera无法实现此事件。


12
IE和Opera无法实现此事件:quirksmode.org/dom/events/index.html
DEfusion 2009年

14
DomSubtreeModified令人垂涎
Adonis K. Kakoulidis


21

这是我最近处理此问题的方式:

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

我知道我参加聚会晚了几年,只是认为我的回答可能会在将来对某些人有所帮助,而无需下载任何插件。


1
我猜从某种角度来说这不是最好的方法,但是我实际上很喜欢它,因为这意味着您可以在动画结束时将其作为回调来触发。调整大小的插件将在整个动画中不断触发,这可能会有所帮助,但也会引起问题。此方法至少可以让您控制何时触发高度检查。
andyface

您的代码到底做什么?为什么我们不能仅在绑定和触发功能中使用您在bind事件内部编写的代码?
user1447420

但这不是自动的,不是吗?
艾伯特·加泰罗(AlbertCatalà)2015年

17

您可以使用MutationObserver课程。

MutationObserver为开发人员提供了一种对DOM中的更改做出反应的方法。它旨在替代DOM3事件规范中定义的突变事件。

示例来源

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

这是正确的答案。还可以看看MutationSummary,它是一个基于MutationObservers的库:github.com/rafaelw/mutation-summary
Christian Bankester 2015年

9

有一个jQuery插件可以很好地处理这个问题

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

如果您调整红色边框的div的大小,这是一个演示它的示例,其中包含有关何时更改高度的不同方案。

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


它很漂亮,但是默认情况下不是每毫秒轮询一次UI以进行更改吗?这样有效吗?
Michael Scott Cuthbert

1
@MichaelScottCuthbert它是很久以前写的,但是我用过setTimeout,所以总的来说是1ms + [执行检查所需的时间],但是想法是要不断地听,一旦你再次触发它,就像一个队列。我敢肯定,我可以做得更好,但时间不多。
2014年

嗯,是的,我看到您距离Vega解决方案(我最终使用的解决方案)和所有DOMSubtreeModified等都早一年了。我虽然从阅读您的代码中学到了很多东西,所以我认为保持链接的价值是值得的。
2014年

7

回应user007:

如果元素的高度由于使用附加到元素上而发生变化,则.append()无需检测高度的变化。只需在将新内容附加到第一个元素的同一函数中添加第二个元素的重定位即可。

如:

工作实例

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

2

您可以创建一个简单的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();

编辑:

这是一个带有类的示例。但是您可以做一些最简单的事情。


0

您可以使用它,但它仅支持Firefox和Chrome。

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


0

很基本,但可以工作:

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

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

仅在调整窗口大小时才会触发此事件,但是OP希望将调整大小事件绑定到特定容器
Fanie Void
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.