【问题标题】:Detecting when a div's height changes using jQuery使用 jQuery 检测 div 的高度何时发生变化
【发布时间】:2010-09-15 10:16:35
【问题描述】:

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

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

【问题讨论】:

  • 我想知道为什么在使用 jQuery 时不想使用插件。
  • @user007 是什么让您的元素大小发生了变化?
  • @roasted 我的 div 高度在附加某些项目时发生变化,附加由 jquery 完成
  • @user007 因此,当您将某些内容附加到 DIV 时,您可以触发 DIV 的自定义调整大小事件。另一种方法(最糟糕的 IMO)可能是使用自定义方法来附加内容,该方法只是扩展本机 jquery append() 方法,将其与回调一起使用,例如
  • @roasted 感谢您的提示。

标签: javascript jquery


【解决方案1】:

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

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

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

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

【讨论】:

  • 不错的解决方案,它使用一个不可见的新元素作为所需目标的叠加层,并利用叠加层上的“滚动”事件来触发更改。
  • 这是唯一适用于所有情况的解决方案,包括内容和属性不变但尺寸发生变化时(例如:使用 css 的百分比尺寸)
  • 迄今为止最好的解决方案。
  • 这不是这里的最高投票答案是一场悲剧。这确实 100% 有效。
  • 这似乎不适用于开始隐藏的元素。
【解决方案2】:

我曾经为 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)

【讨论】:

  • 这解决了如果您手动调整 div 大小的问题,这并没有解决原来的问题,不是吗?如果您动态添加内容,它不会检测到高度变化:jsfiddle.net/aD49d/25
  • 我也想知道是否有办法使这项工作适用于动态内容。
  • @JoeCoder 此属性代码依赖于有用户操作时由浏览器触发的 DOM 事件。但是,该示例中的动态内容以编程方式包含在内,遗憾的是不会触发任何事件。 “轮询”在这里似乎是另一个更简单的选项.. 包含动态内容后,其他选项将能够手动触发。
【解决方案3】:

你可以使用 DOMSubtreeModified 事件

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

但是,即使尺寸不变,它也会触发,并且在触发时重新分配位置可能会影响性能。根据我使用这种方法的经验,检查尺寸是否发生变化的成本较低,因此您可以考虑将两者结合起来。

或者,如果您直接更改 div(而不是用户输入以不可预知的方式更改 div,例如它是否是 contentEditable),您只需在执行此操作时触发自定义事件。

缺点:IE 和 Opera 没有实现这个事件。

【讨论】:

【解决方案4】:

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

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

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

【讨论】:

  • 我想在某些方面这不是最好的方法,但我实际上非常喜欢它,因为这意味着您可以在动画结束时将其作为回调触发。调整大小插件将在整个动画中持续触发,这可能会有所帮助,但也可能会导致问题。这种方法至少可以让您控制何时触发高度检查。
  • 你的代码到底是做什么的?为什么我们不能只在绑定和触发的函数中使用您在绑定事件中编写的代码?
  • 但这不是自动的,不是吗?
  • 这个答案会随着文字的澄清而大大改善!解释绑定做什么,何时触发函数等。而不是神秘的代码响应。
【解决方案5】:

您可以使用MutationObserver 类。

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

示例 (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】:

回复 user007:

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

如:

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

【讨论】:

    【解决方案7】:

    你可以做一个简单的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();

    编辑:

    这是一个类的例子。但是你可以做一些最简单的事情。

    【讨论】:

      【解决方案8】:

      现在您还可以使用 Web API ResizeObserver

      简单示例:

      const resizeObserver = new ResizeObserver(() => {
          console.log('size changed');
      });
      
      resizeObserver.observe(document.querySelector('#myElement'));
      

      【讨论】:

        【解决方案9】:

        你可以使用它,但它只支持 Firefox 和 Chrome。

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

        【讨论】:

          【解决方案10】:

          非常基本但有效:

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

          【讨论】:

          • 只有在调整窗口大小时才会触发此事件,但 OP 希望将调整大小事件绑定到特定容器
          猜你喜欢
          • 1970-01-01
          • 2010-09-26
          • 1970-01-01
          • 2012-02-20
          • 1970-01-01
          • 2013-11-25
          • 2016-12-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多