如何检测DIV的尺寸变化?


351

我有以下示例html,有一个DIV,其宽度为100%。它包含一些元素。在执行窗口调整大小时,内部元素可能会重新放置,并且div的尺寸可能会更改。我问是否有可能挂钩div的尺寸更改事件?以及如何做到这一点?我目前将回调函数绑定到目标DIV上的jQuery resize事件,但是,没有控制台日志输出,请参见以下内容:

调整大小之前 在此处输入图片说明

<html>
<head>
    <script type="text/javascript" language="javascript" src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
    <script type="text/javascript" language="javascript">
            $('#test_div').bind('resize', function(){
                console.log('resized');
            });
    </script>
</head>
<body>
    <div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
        <input type="button" value="button 1" />
        <input type="button" value="button 2" />
        <input type="button" value="button 3" />
    </div>
</body>
</html>

7
这将不起作用,因为您正在将resize事件绑定到指定的div元素。但是resize事件将触发窗口,而不触发您的元素。
法提赫·阿塞特

您可以setInterval在此处使用它作为可能的解决方案。工作完成后,您始终可以绑定clearInterval到单击按钮以停止循环。
彼得·达米斯

1
自2020年以来,ResizeObserver可在除IE之外的所有主要浏览器(Chrome,Safari,Firefox,Edge)中使用。caniuse.com/#feat=resizeobserver

Answers:


263

有一种非常有效的方法来确定元素的大小是否已更改。

http://marcj.github.io/css-element-queries/

该库具有ResizeSensor可用于调整大小检测的类。
它使用基于事件的方法,因此该死的速度很快,并且不会浪费CPU时间。

例:

new ResizeSensor(jQuery('#divId'), function(){ 
    console.log('content dimension changed');
});

请不要使用jQuery onresize插件,因为它setTimeout()与在循环中读取DOM clientHeight/ clientWidth属性结合使用以检查更改。
这是令人难以置信的缓慢且不准确,因为它会引起布局抖动

披露:我直接与此图书馆有联系。


8
@jake,现已实现IE11支持。
马克·施密特

15
@Aletheios,您应该仔细看看。requestAnimationFrame不是用于慢速尺寸检测,而是完全相反:它可以平滑所有基于真实事件的大小调整传感器触发的所有极端事件,以节省CPU时间。请参阅github.com/marcj/css-element-queries/blob/master/src/…上的
Marc J. Schmidt

6
@Aletheios我想您会漏掉一点:setTimeout不仅不准确,而且像地狱般缓慢。检查一个简单布尔值的requestAnimationFrame比setTimeout始终检查DOM属性的速度快几个数量级。在setTimeout旁边还每隔几毫秒调用一次。
马克·施密特

9
@Orwellophile您显然一无所知。如果您不知道内部答案如何,请停止投票。再次:css-element-query:使用实际的大小调整事件,每次尺寸更改时都会触发该事件。由于您会收到太多事件(例如,拖放操作),因此它添加了requestAnimationFrame检查简单的布尔变量,以将触发的事件平滑化为1 / frame。jQuery插件:使用setTimeout来检查所有时间的DOM布局道具(clientHeight等),其中每次检查都非常缓慢,但需要经常检查以具有相同的功能。
马克·施密特

9
@ Aletheios,@ Orwellophile,以及任何可能被他们误导的人:requestAnimationFramevs setTimeout无关紧要,此库不会循环requestAnimationFrame仅用于消除/限制调用回调的频率,它不会轮询。理论上,MutationObserver可以达到类似的效果,但与此不同的是,不能在较旧的浏览器中使用。这是非常聪明的。
汉城汉城

250

对此的新标准是Chrome 64中提供的Resize Observer api。

function outputsize() {
 width.value = textbox.offsetWidth
 height.value = textbox.offsetHeight
}
outputsize()

new ResizeObserver(outputsize).observe(textbox)
Width: <output id="width">0</output><br>
Height: <output id="height">0</output><br>
<textarea id="textbox">Resize me</textarea><br>

调整观察者大小

规格:https//wicg.github.io/ResizeObserver

Polyfills:https//github.com/WICG/ResizeObserver/issues/3

Firefox问题:https//bugzil.la/1272409

Safari问题:http//wkb.ug/157743

当前支持:http : //caniuse.com/#feat=resizeobserver


3
尚不适用于生产站点,因为目前只有Chrome支持。但是绝对是这里最好的解决方案!顺便说一句,这里是实施状态的简要概述:chromestatus.com/feature/5705346022637568
Philipp

8
@Philipp有一个polyfill。
Daniel Herr

2
似乎它仍然是所有浏览器中的实验功能caniuse.com/#feat=resizeobserver
Francesc Rosas

5
即使在回答了此问题的2年后,浏览器的支持也很惨淡:caniuse.com/#search=resizeobserver
Scrimothy

2
在最新版的Chrome和FF中像魅力一样工作。
KlemenTušar,

32

您必须将resize事件绑定到window对象上,而不是通用html元素上。

然后,您可以使用以下代码:

$(window).resize(function() {
    ...
});

在回调函数中,您可以检查div呼叫的新宽度

$('.a-selector').width();

因此,您的问题的答案是否定的,您无法将resize事件绑定到div。


123
这个答案还不够好。如果不调整任何窗口大小,可能会发生大小更改。完全没有
VSYNC

9
例如,当您有一个splitter元素或仅将一些文本或其他内容附加到该元素时。
君特Zöchbauer

@anu不正确,您可以通过javascript进行DOM修改,例如将CSS应用于新结构,从而导致不同的布局-每个容器的大小。
Antoniossss

29

从长远来看,您将可以使用ResizeObserver

new ResizeObserver(callback).observe(element);

不幸的是,当前许多浏览器默认都不支持它。

同时,您可以使用以下功能。因为,大多数元素大小的更改将来自于调整窗口大小或更改DOM中的某些内容。您可以使用窗口的resize事件来监听窗口的大小调整,也可以使用MutationObserver来监听DOM的更改。

这是一个函数示例,当所提供的元素的大小由于这些事件中的任何一个而改变时,该函数将回调您:

var onResize = function(element, callback) {
  if (!onResize.watchedElementData) {
    // First time we are called, create a list of watched elements
    // and hook up the event listeners.
    onResize.watchedElementData = [];

    var checkForChanges = function() {
      onResize.watchedElementData.forEach(function(data) {
        if (data.element.offsetWidth !== data.offsetWidth ||
            data.element.offsetHeight !== data.offsetHeight) {
          data.offsetWidth = data.element.offsetWidth;
          data.offsetHeight = data.element.offsetHeight;
          data.callback();
        }
      });
    };

    // Listen to the window's size changes
    window.addEventListener('resize', checkForChanges);

    // Listen to changes on the elements in the page that affect layout 
    var observer = new MutationObserver(checkForChanges);
    observer.observe(document.body, { 
      attributes: true,
      childList: true,
      characterData: true,
      subtree: true 
    });
  }

  // Save the element we are watching
  onResize.watchedElementData.push({
    element: element,
    offsetWidth: element.offsetWidth,
    offsetHeight: element.offsetHeight,
    callback: callback
  });
};

1
不幸的是,似乎MutationObserver无法检测Shadow DOM中的更改。
Ajedi32

@nkron,不幸的是,如果使用CSS3 resize,则当用户手动调整大小时可能会发生调整大小。无法捕获此事件。
Pacerier '16

@ Ajedi32是的,但是您可以在ShadowDOM内部使用MutationObserver。我的意思是body,您可以直接观看元素,而不是像本例中那样观看。实际上,与观察整个身体相比,这更加高效和高效。
trusktr

@ Ajedi32好吧,唯一的问题是,如果Shadow DOM树已关闭,则您将无法访问内部,但是我认为这通常不是您需要做的事情,并且如果您需要观察像这样的闭树,那么设计中可能会有问题。理想情况下,您只需要观察自己可以访问的元素即可。需要您观察其内部大小的Shadow-DOM组件可能未正确设计。你有一个具体的例子吗?如果是这样,也许我可以帮忙提出一个解决方案(因为我也对此感兴趣,但是还没有示例)。
trusktr

@trusktr我目前没有MCVE,但是基本上任何Shadow DOM元素(由于某些用户输入而可以更改其大小)都足以触发此问题。例如,一个框,在单击时会展开并带有一些其他信息。请注意,我观察的是页面,而不是单个元素,因为无论页面大小如何,我都想自动向下滚动。Shadow DOM元素扩展只是页面可能变长的许多可能原因之一。
Ajedi32 '16

24

ResizeSensor.js是一个巨大的库的一部分,但我将其功能简化为THIS

function ResizeSensor(element, callback)
{
    let zIndex = parseInt(getComputedStyle(element));
    if(isNaN(zIndex)) { zIndex = 0; };
    zIndex--;

    let expand = document.createElement('div');
    expand.style.position = "absolute";
    expand.style.left = "0px";
    expand.style.top = "0px";
    expand.style.right = "0px";
    expand.style.bottom = "0px";
    expand.style.overflow = "hidden";
    expand.style.zIndex = zIndex;
    expand.style.visibility = "hidden";

    let expandChild = document.createElement('div');
    expandChild.style.position = "absolute";
    expandChild.style.left = "0px";
    expandChild.style.top = "0px";
    expandChild.style.width = "10000000px";
    expandChild.style.height = "10000000px";
    expand.appendChild(expandChild);

    let shrink = document.createElement('div');
    shrink.style.position = "absolute";
    shrink.style.left = "0px";
    shrink.style.top = "0px";
    shrink.style.right = "0px";
    shrink.style.bottom = "0px";
    shrink.style.overflow = "hidden";
    shrink.style.zIndex = zIndex;
    shrink.style.visibility = "hidden";

    let shrinkChild = document.createElement('div');
    shrinkChild.style.position = "absolute";
    shrinkChild.style.left = "0px";
    shrinkChild.style.top = "0px";
    shrinkChild.style.width = "200%";
    shrinkChild.style.height = "200%";
    shrink.appendChild(shrinkChild);

    element.appendChild(expand);
    element.appendChild(shrink);

    function setScroll()
    {
        expand.scrollLeft = 10000000;
        expand.scrollTop = 10000000;

        shrink.scrollLeft = 10000000;
        shrink.scrollTop = 10000000;
    };
    setScroll();

    let size = element.getBoundingClientRect();

    let currentWidth = size.width;
    let currentHeight = size.height;

    let onScroll = function()
    {
        let size = element.getBoundingClientRect();

        let newWidth = size.width;
        let newHeight = size.height;

        if(newWidth != currentWidth || newHeight != currentHeight)
        {
            currentWidth = newWidth;
            currentHeight = newHeight;

            callback();
        }

        setScroll();
    };

    expand.addEventListener('scroll', onScroll);
    shrink.addEventListener('scroll', onScroll);
};

如何使用它:

let container = document.querySelector(".container");
new ResizeSensor(container, function()
{
    console.log("dimension changed:", container.clientWidth, container.clientHeight);
});

这就是图表js所做的。
Antoniossss18年

感谢压缩。我将尝试一下:)
Tony K.

该表达式中缺少一些内容parseInt( getComputedStyle(element) )
GetFree

2
我很困惑“如何让zIndex = parseInt(getComputedStyle(element));” 有效?我假设您的意思是:“让zIndex = parseInt(getComputedStyle(element).zIndex);
Ryan Badour

1
上面的解决方案/代码不会检测所有调整大小的事件(例如,如果将容器调整为固定大小,则不会检测子事件的调整大小。请参阅jsfiddle.net/8md2rfsy/1)。接受的答案有效(取消注释相应的行)。
newBee

21

我不推荐setTimeout()hack,因为它会降低性能!相反,您可以使用 DOM突变观察器来监听Div大小的变化。

JS:

var observer = new MutationObserver(function(mutations) {
    console.log('size changed!');
  });
  var target = document.querySelector('.mydiv');
  observer.observe(target, {
    attributes: true
  });

HTML:

<div class='mydiv'>
</div>

这是小提琴
尝试更改div的大小。


您可以将方法进一步包装在方法中debounce以提高效率。debounce将每隔x毫秒触发一次您的方法,而不是每隔一毫秒触发一次DIV调整大小。


9
唯一的问题是,除非元素发生实际突变,否则它不会报告更改。如果元素由于添加了其他元素而调整了大小,则将无法使用。
Tony K.

我同意@TonyK。,这是MutationObserver的唯一问题,现在我正在寻找元素调整大小的库
Murhaf Sousli

@JerryGoyal当div包含<img>标记时,它不起作用。在第一种情况下,不会加载图像,并且div大小设置为0,并且在加载后div大小会更改,但是不会触发观察者
Santhosh

15

最好的解决方案是使用所谓的元素查询。但是,它们不是标准的,没有规范-如果您想这样做,唯一的选择是使用一种可用的polyfills /库。

元素查询背后的想法是允许页面上的特定容器响应提供给它的空间。这将允许编写一次组件,然后将其放置在页面上的任何位置,同时它将其内容调整为当前大小。无论窗口大小是多少。这是我们在元素查询和媒体查询之间看到的第一个区别。每个人都希望在某个时候可以创建一个规范,以规范元素查询(或达到相同目标的东西),并使它们本机,干净,简单且健壮。大多数人都认为媒体查询非常有限,对模块化设计和真正的响应能力没有帮助。

有一些polyfills /库以不同方式解决问题(尽管可以称为替代方法,而不是解决方案):

我已经看到了针对类似问题的其他解决方案。通常他们使用计时器或引擎盖下的窗口/视口大小,这不是真正的解决方案。此外,我认为理想上应该主要在CSS中解决,而不是在javascript或html中解决。


+1用于元素查询,但我不希望很快见到它们。AFAIK目前甚至还没有草案规范……也许我们其中一个感兴趣的团体应该将其放在一起提交?
罗布·埃文斯

1
当然,这是一个好主意。到达最终版本需要很长时间,需要引起很多注意。对我而言,以一种好的方式设计它似乎并不重要。跨浏览器的兼容性,循环依赖项,调试,可读性和维护性等。因此,让我们尽早开始:)
Stan,2015年

@Stan,我认为通过对元素查询的全部内容进行详细说明,可以更好地解决此问题。
Pacerier '16

15

当MarcJ的解决方案不起作用时,我发现此库可以工作:

https://github.com/sdecima/javascript-detect-element-resize

它非常轻巧,甚至可以通过CSS或HTML加载/渲染来检测自然大小。

代码示例(从链接中获取):

<script type="text/javascript" src="detect-element-resize.js"></script>
<script type="text/javascript">
  var resizeElement = document.getElementById('resizeElement'),
      resizeCallback = function() {
          /* do something */
      };
  addResizeListener(resizeElement, resizeCallback);
  removeResizeListener(resizeElement, resizeCallback);
</script>

就是这个。147行,使用滚动事件。如果您想获得有关如何最好地检测div尺寸变化的完整而真实的答案,请通读此代码。提示:它不是“仅使用此库”。
瑟夫·里德

1
人们在尝试使用此库之前应该先看一下这个问题
路易

13

看看这个http://benalman.com/code/projects/jquery-resize/examples/resize/

它有各种各样的例子。尝试调整窗口大小,并查看容器元素中的元素如何调整。

js小提琴的示例解释了如何使其工作。
看看这个小提琴http://jsfiddle.net/sgsqJ/4/

在该事件中,将resize()事件绑定到具有“ test”类的元素以及窗口对象,并在窗口对象的resize回调中调用$('。test')。resize()。

例如

$('#test_div').bind('resize', function(){
            console.log('resized');
});

$(window).resize(function(){
   $('#test_div').resize();
});

有趣。jsfiddle始终在打开检查器的情况下崩溃chrome,然后单击“添加更多文本”链接。Firefox抛出“太多递归”错误。
EricP

3
请不要使用jQuery的大小调整插件。这确实很慢,而且也不准确。查看我的答案以获得更好的解决方案。
马克·施密特

24
这不会直接检测尺寸变化。它只是调整大小的事件侦听器的副产品。尺寸变化可以通过许多其他方式发生。
vsync

4
如果div的大小调整来自样式或dom的更改,而不是窗口调整大小,该怎么办?
2015年

9

您可以使用iframeobject使用contentWindowcontentDocument调整大小。没有setIntervalsetTimeout

步骤:

  1. 将元素位置设置为 relative
  2. 在透明的绝对隐藏的IFRAME中添加
  3. IFRAME.contentWindow- onresize事件

HTML的示例:

<div style="height:50px;background-color:red;position:relative;border:1px solid red">
<iframe style=width:100%;height:100%;position:absolute;border:none;background-color:transparent allowtransparency=true>
</iframe>
This is my div
</div>

Javascript:

$('div').width(100).height(100);
$('div').animate({width:200},2000);

$('object').attr({
    type : 'text/html'
})
$('object').on('resize,onresize,load,onload',function(){
    console.log('ooooooooonload')
})

$($('iframe')[0].contentWindow).on('resize',function(){
    console.log('div changed')
})

运行示例

JsFiddle:https://jsfiddle.net/qq8p470d/


查看更多:


1
对于未使用jquery的用户的注释IFRAME.contentWindowonload事件在iframe上触发之前不可用。另外,您可能要添加样式visibility:hidden;,因为iframe可能会将鼠标输入阻止到其后面的元素上(至少在IE中似乎是“浮动”的)。
詹姆斯·威尔金斯

3
尽管这可行,但这是一个重量级的解决方案,其开销只是创建一个新的浏览上下文以观察大小变化。同样,在某些情况下,更改display元素的属性也不理想或不可行。
trusktr'8

同意,这是如上所述的可怕解决方案
29er 2016年

怎么写这么可怕的解决方案?
Aminadav Glickshtein

此方法适用于需要动态调整内容大小的视频播放器和音频播放器。我正在使用此方法调整waveurfer.js输出的大小。
David Clews

8

仅窗口对象会生成“调整大小”事件。我唯一知道要执行的操作的方法是运行一个间隔计时器,该计时器会定期检查大小。


7

var div = document.getElementById('div');
div.addEventListener('resize', (event) => console.log(event.detail));

function checkResize (mutations) {
    var el = mutations[0].target;
    var w = el.clientWidth;
    var h = el.clientHeight;
    
    var isChange = mutations
      .map((m) => m.oldValue + '')
      .some((prev) => prev.indexOf('width: ' + w + 'px') == -1 || prev.indexOf('height: ' + h + 'px') == -1);

    if (!isChange)
      return;

    var event = new CustomEvent('resize', {detail: {width: w, height: h}});
    el.dispatchEvent(event);
}

var observer = new MutationObserver(checkResize); 
observer.observe(div, {attributes: true, attributeOldValue: true, attributeFilter: ['style']});
#div {width: 100px; border: 1px solid #bbb; resize: both; overflow: hidden;}
<div id = "div">DIV</div>


7

与这个问题一样古老,这在大多数浏览器中仍然是一个问题。

就像其他人所说的那样,Chrome 64+现在本地附带了Resize Observes,但是该规范仍在微调中,并且Chrome当前(截至2019-01-29)目前落后于该规范的最新版本。

我已经看到了很多很好的ResizeObserver填充,但是,其中一些并没有严格遵循规范,而另一些则存在一些计算问题。

我非常需要这种行为来创建一些可在任何应用程序中使用的响应式Web组件。为了使它们正常工作,他们需要始终了解它们的尺寸,因此ResizeObservers听起来很理想,我决定创建一个尽可能符合规格的polyfill。

回购:https : //github.com/juggle/resize-observer

演示:https//codesandbox.io/s/myqzvpmmy9


对于任何处理IE11 +浏览器兼容性的人来说,这无疑是一个困扰。
ekfuhrmann


3

这篇博客文章帮助我有效地检测DOM元素的大小变化。

http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/

如何使用此代码...

AppConfig.addResizeListener(document.getElementById('id'), function () {
  //Your code to execute on resize.
});

该示例使用的打包代码...

var AppConfig = AppConfig || {};
AppConfig.ResizeListener = (function () {
    var attachEvent = document.attachEvent;
    var isIE = navigator.userAgent.match(/Trident/);
    var requestFrame = (function () {
        var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
            function (fn) { return window.setTimeout(fn, 20); };
        return function (fn) { return raf(fn); };
    })();

    var cancelFrame = (function () {
        var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
               window.clearTimeout;
        return function (id) { return cancel(id); };
    })();

    function resizeListener(e) {
        var win = e.target || e.srcElement;
        if (win.__resizeRAF__) cancelFrame(win.__resizeRAF__);
        win.__resizeRAF__ = requestFrame(function () {
            var trigger = win.__resizeTrigger__;
            trigger.__resizeListeners__.forEach(function (fn) {
                fn.call(trigger, e);
            });
        });
    }

    function objectLoad(e) {
        this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__;
        this.contentDocument.defaultView.addEventListener('resize', resizeListener);
    }

    AppConfig.addResizeListener = function (element, fn) {
        if (!element.__resizeListeners__) {
            element.__resizeListeners__ = [];
            if (attachEvent) {
                element.__resizeTrigger__ = element;
                element.attachEvent('onresize', resizeListener);
            } else {
                if (getComputedStyle(element).position === 'static') element.style.position = 'relative';
                var obj = element.__resizeTrigger__ = document.createElement('object');
                obj.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;');
                obj.__resizeElement__ = element;
                obj.onload = objectLoad;
                obj.type = 'text/html';
                if (isIE) element.appendChild(obj);
                obj.data = 'about:blank';
                if (!isIE) element.appendChild(obj);
            }
        }
        element.__resizeListeners__.push(fn);
    };

    AppConfig.removeResizeListener = function (element, fn) {
        element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
        if (!element.__resizeListeners__.length) {
            if (attachEvent) element.detachEvent('onresize', resizeListener);
            else {
                element.__resizeTrigger__.contentDocument.defaultView.removeEventListener('resize', resizeListener);
                element.__resizeTrigger__ = !element.removeChild(element.__resizeTrigger__);
            }
        }
    }
})();

注意:AppConfig是我用于组织可重用功能的名称空间/对象。随时搜索和替换您想要的名称。


3

我的jQuery插件不仅对启用所有元素的“调整大小”事件window

https://github.com/dustinpoissant/ResizeTriggering

$("#myElement") .resizeTriggering().on("resize", function(e){
  // Code to handle resize
}); 

1
您的链接指向的位置不再存在。我已经搜索了插件的名称,并找到了一个与您的描述相对应的页面。由于您似乎是该插件的作者,因此我还编辑了答案的语言,以明确表明这是您的工作。该站点的规则是这样的,当您编写答案时建议使用您开发的内容,则必须使关系明确。
路易

这不是一个很好的解决方案,因为您一次又一次地在setTimer中运行某些功能,这意味着即使没有任何反应,浏览器也会不断消耗CPU。笔记本电脑和手机所有者受益于仅在采取某些操作(例如使用onScroll事件)时才使用浏览器事件的解决方案。
Roman Zenka '18

2

您可以尝试以下代码段中的代码,它使用普通的javascript满足了您的需求。(运行代码段,然后单击“整页”链接以触发有关div调整大小的警报,如果您要对其进行测试。)。

基于这是setInterval100毫秒的事实,我敢说我的PC并没有发现它占用过多的CPU。(在测试时,Chrome中所有打开的标签页使用的CPU总数为0.1%。)但是话又说回来,这仅适用于一个div,如果您想对大量元素执行此操作,则可以,这可能会非常占用CPU。

无论如何,您始终可以使用click事件来停止div调整大小的嗅探

var width = 0; 
var interval = setInterval(function(){
if(width <= 0){
width = document.getElementById("test_div").clientWidth;
} 
if(document.getElementById("test_div").clientWidth!==width) {   
  alert('resized div');
  width = document.getElementById("test_div").clientWidth;
}    

}, 100);
<div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
        <input type="button" value="button 1" />
        <input type="button" value="button 2" />
        <input type="button" value="button 3" />
</div>

您可以检查小提琴

更新

var width = 0; 
function myInterval() {
var interval = setInterval(function(){
if(width <= 0){
width = document.getElementById("test_div").clientWidth;
} 
if(document.getElementById("test_div").clientWidth!==width) {   
  alert('resized');
  width = document.getElementById("test_div").clientWidth;
}    

}, 100);
return interval;
}
var interval = myInterval();
document.getElementById("clickMe").addEventListener( "click" , function() {
if(typeof interval!=="undefined") {
clearInterval(interval);
alert("stopped div-resize sniffing");
}
});
document.getElementById("clickMeToo").addEventListener( "click" , function() {
myInterval();
alert("started div-resize sniffing");
});
<div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
        <input type="button" value="button 1" id="clickMe" />
        <input type="button" value="button 2" id="clickMeToo" />
        <input type="button" value="button 3" />
</div>

更新的小提琴


2

这几乎是最佳答案的精确副本,但它不是链接,而只是重要的代码部分,翻译为IMO更易读和理解。其他一些小的更改包括使用cloneNode(),而不是将html放入js字符串中。小东西,但是您可以照原样复制并粘贴它,它将起作用。

它的工作方式是通过使两个不可见的div填充您正在观看的元素,然后在每个div中放置一个触发器,并设置一个滚动位置,该滚动位置将在尺寸改变时触发滚动更改。

真正的功劳归功于Marc J,但是,如果您只是在寻找相关的代码,这里是:

    window.El = {}

    El.resizeSensorNode = undefined;
    El.initResizeNode = function() {
        var fillParent = "display: block; position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; z-index: -1; visibility: hidden;";
        var triggerStyle = "position: absolute; left: 0; top: 0; transition: 0s;";

        var resizeSensor = El.resizeSensorNode = document.createElement("resizeSensor");
        resizeSensor.style = fillParent;

        var expandSensor = document.createElement("div");
        expandSensor.style = fillParent;
        resizeSensor.appendChild(expandSensor);

        var trigger = document.createElement("div");
        trigger.style = triggerStyle;
        expandSensor.appendChild(trigger);

        var shrinkSensor = expandSensor.cloneNode(true);
        shrinkSensor.firstChild.style = triggerStyle + " width: 200%; height: 200%";
        resizeSensor.appendChild(shrinkSensor);
    }


    El.onSizeChange = function(domNode, fn) {
        if (!domNode) return;
        if (domNode.resizeListeners) {
            domNode.resizeListeners.push(fn);
            return;
        }

        domNode.resizeListeners = [];
        domNode.resizeListeners.push(fn);

        if(El.resizeSensorNode == undefined)
            El.initResizeNode();

        domNode.resizeSensor = El.resizeSensorNode.cloneNode(true);
        domNode.appendChild(domNode.resizeSensor);

        var expand = domNode.resizeSensor.firstChild;
        var expandTrigger = expand.firstChild;
        var shrink = domNode.resizeSensor.childNodes[1];

        var reset = function() {
            expandTrigger.style.width = '100000px';
            expandTrigger.style.height = '100000px';

            expand.scrollLeft = 100000;
            expand.scrollTop = 100000;

            shrink.scrollLeft = 100000;
            shrink.scrollTop = 100000;
        };

        reset();

        var hasChanged, frameRequest, newWidth, newHeight;
        var lastWidth = domNode.offsetWidth;
        var lastHeight = domNode.offsetHeight;


        var onResized = function() {
            frameRequest = undefined;

            if (!hasChanged) return;

            lastWidth = newWidth;
            lastHeight = newHeight;

            var listeners = domNode.resizeListeners;
            for(var i = 0; listeners && i < listeners.length; i++) 
                listeners[i]();
        };

        var onScroll = function() {
            newWidth = domNode.offsetWidth;
            newHeight = domNode.offsetHeight;
            hasChanged = newWidth != lastWidth || newHeight != lastHeight;

            if (hasChanged && !frameRequest) {
                frameRequest = requestAnimationFrame(onResized);
            }

            reset();
        };


        expand.addEventListener("scroll", onScroll);
        shrink.addEventListener("scroll", onScroll);
    }

1

纯Javascript解决方案,但仅在使用css resize按钮调整元素大小时才有效:

  1. 使用offsetWidthoffsetHeight存储元素大小;
  2. 在此元素上添加onclick事件侦听器;
  3. 触发后,比较当前值offsetWidthoffsetHeight存储的值,如果不同,则执行所需操作并更新这些值。

1

这是@nkron解决方案的简化版本,适用于单个元素(而不是@nkron答案中的元素数组,我不需要复杂性)。

function onResizeElem(element, callback) {    
  // Save the element we are watching
  onResizeElem.watchedElementData = {
    element: element,
    offsetWidth: element.offsetWidth,
    offsetHeight: element.offsetHeight,
    callback: callback
  };

  onResizeElem.checkForChanges = function() {
    const data = onResizeElem.watchedElementData;
    if (data.element.offsetWidth !== data.offsetWidth || data.element.offsetHeight !== data.offsetHeight) {
      data.offsetWidth = data.element.offsetWidth;
      data.offsetHeight = data.element.offsetHeight;
      data.callback();
    }
  };

  // Listen to the window resize event
  window.addEventListener('resize', onResizeElem.checkForChanges);

  // Listen to the element being checked for width and height changes
  onResizeElem.observer = new MutationObserver(onResizeElem.checkForChanges);
  onResizeElem.observer.observe(document.body, {
    attributes: true,
    childList: true,
    characterData: true,
    subtree: true
  });
}

事件侦听器和观察者可以通过以下方式删除:

window.removeEventListener('resize', onResizeElem.checkForChanges);
onResizeElem.observer.disconnect();

0
jQuery(document).ready( function($) {

function resizeMapDIVs() {

// check the parent value...

var size = $('#map').parent().width();



if( $size < 640 ) {

//  ...and decrease...

} else {

//  ..or increase  as necessary

}

}

resizeMapDIVs();

$(window).resize(resizeMapDIVs);

});

0

使用Bharat Patil答案只需在绑定回调内部返回false即可防止最大堆栈错误,请参见以下示例:

$('#test_div').bind('resize', function(){
   console.log('resized');
   return false;
});

0

这是一个非常老的问题,但我认为我会为此提出解决方案。

我尝试使用它,ResizeSensor因为每个人似乎对此都有很大的迷恋。在实施之后,我意识到在元素查询的幕后要求有问题的元素具有位置relative或对其absolute应用,这对我的情况不起作用。

我最终使用Rxjs interval代替了以前的实现setTimeoutrequestAnimationFrame类似的实现来处理此问题。

间隔的可观察风格的好处是您可以修改流,但是可以处理其他任何可观察的事物。对我来说,一个基本的实现就足够了,但是您可能会发疯并进行各种合并等。

在下面的示例中,我正在跟踪内部(绿色)div的宽度变化。它的宽度设置为50%,但最大宽度为200px。拖动滑块会影响包装器(灰色)div的宽度。您可以看到,只有内部div的宽度发生变化时,可观察对象才会触发,只有外部div的宽度小于400px时才会发生。

const { interval } = rxjs;
const { distinctUntilChanged, map, filter } = rxjs.operators;


const wrapper = document.getElementById('my-wrapper');
const input = document.getElementById('width-input');




function subscribeToResize() {
  const timer = interval(100);
  const myDiv = document.getElementById('my-div');
  const widthElement = document.getElementById('width');
  const isMax = document.getElementById('is-max');
  
  /*
    NOTE: This is the important bit here 
  */
  timer
    .pipe(
      map(() => myDiv ? Math.round(myDiv.getBoundingClientRect().width) : 0),
      distinctUntilChanged(),
      // adding a takeUntil(), here as well would allow cleanup when the component is destroyed
    )
      .subscribe((width) => {        
        widthElement.innerHTML = width;
        isMax.innerHTML = width === 200 ? 'Max width' : '50% width';

      });
}

function defineRange() {
  input.min = 200;
  input.max = window.innerWidth;
  input.step = 10;
  input.value = input.max - 50;
}

function bindInputToWrapper() {
  input.addEventListener('input', (event) => {
    wrapper.style.width = `${event.target.value}px`;
  });
}

defineRange();
subscribeToResize();
bindInputToWrapper();
.inner {
  width: 50%;
  max-width: 200px;
}




/* Aesthetic styles only */

.inner {
  background: #16a085;
}

.wrapper {
  background: #ecf0f1;
  color: white;
  margin-top: 24px;
}

.content {
  padding: 12px;
}

body {
  
  font-family: sans-serif;
  font-weight: bold;
}
<script src="https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"></script>

<h1>Resize Browser width</h1>

<label for="width-input">Adjust the width of the wrapper element</label>
<div>
  <input type="range" id="width-input">
</div>

<div id="my-wrapper" class="wrapper">
  <div id="my-div" class="inner">
    <div class="content">
      Width: <span id="width"></span>px
      <div id="is-max"></div>  
    </div>
  </div>
</div>


-1

Window.onResize存在于规范,但你总是可以利用IFrame来产生新Window的DIV中的对象。

请检查此答案。有一个新的小jquery插件,可移植且易于使用。您始终可以检查源代码以了解其完成方式。

<!-- (1) include plugin script in a page -->
<script src="/src/jquery-element-onresize.js"></script>

// (2) use the detectResizing plugin to monitor changes to the element's size:
$monitoredElement.detectResizing({ onResize: monitoredElement_onResize });

// (3) write a function to react on changes:
function monitoredElement_onResize() {    
    // logic here...
}

如果您具有可调整大小的div,那么这是非常无效的解决方案。
suricactus

-1

我以为无法完成,但后来我想到了,您可以通过style =“ resize:both;”手动调整div的大小。为了做到这一点,您必须单击它,因此添加了一个onclick函数来检查元素的高度和宽度,并且它起作用了。仅使用5行纯JavaScript(确保它甚至可以更短) http://codepen.io/anon/pen/eNyyVN

<div id="box" style="
                height:200px; 
                width:640px;
                background-color:#FF0066;
                resize: both;
                overflow: auto;" 
                onclick="myFunction()">
    <p id="sizeTXT" style="
                font-size: 50px;">
       WxH
    </p>
    </div>

<p>This my example demonstrates how to run a resize check on click for resizable div.</p>

<p>Try to resize the box.</p>


<script>
function myFunction() {
var boxheight = document.getElementById('box').offsetHeight;
var boxhwidth = document.getElementById('box').offsetWidth;
var txt = boxhwidth +"x"+boxheight;
document.getElementById("sizeTXT").innerHTML = txt;
}
</script>

2
这仅会计算触发事件的点击事件,这不属于问题的要求。
罗布·埃文斯
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.