如何检测DIV的维度改变?

IT技术 javascript jquery html
2021-01-11 23:24:47

我有以下示例 html,有一个宽度为 100% 的 DIV。它包含一些元素。在执行窗口大小调整时,内部元素可能会重新定位,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>
6个回答

一个新的标准是 Resize Observer api,它在 Chrome 64 中可用。

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 : //developer.mozilla.org/en-US/docs/Web/API/Resize_Observer_API

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

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

Polyfills:https : //github.com/pelotoncycle/resize-observer https://github.com/que-etc/resize-observer-polyfill https://github.com/juggle/resize-observer

现在所有主要浏览器都支持 ResizeObserver。
2021-03-15 23:24:47
对生产站点还没有用,因为目前只有 Chrome 支持它。但绝对是这里最好的解决方案!顺便说一句,这里是实施状态的快速概览:chromestatus.com/feature/5705346022637568
2021-03-19 23:24:47
@Philipp 有一个 polyfill。
2021-03-23 23:24:47
即使在这个答案之后 2 年,浏览器支持也很惨淡:caniuse.com/#search=resizeobserver
2021-03-27 23:24:47
现在可以在 Firefox、chrome、safari、Opera 中使用。
2021-04-03 23:24:47

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

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属性结合使用以检查更改。
这是令人难以置信的缓慢和不准确,因为它会导致布局颠簸

披露:我与这个图书馆直接相关。

@Aletheios 我猜你错过了一点:setTimeout 不仅不准确,而且慢得要命。检查简单布尔值的 requestAnimationFrame 比始终检查 DOM 属性的 setTimeout 快几个数量级。除此之外, setTimeout 也每隔几毫秒调用一次。
2021-03-13 23:24:47
@jake,现在实现了 IE11 支持。
2021-03-26 23:24:47
@Aletheios、@Orwellophile 以及任何可能被他们误导的人:requestAnimationFramevssetTimeout无关紧要,这个库不会循环requestAnimationFrame仅用于消除/限制调用回调的频率,它不轮询MutationObserver 理论上可以用于类似的效果,但不能在旧浏览器中使用,与此不同。这非常聪明。
2021-03-28 23:24:47
@Aletheios 你应该仔细看看。requestAnimationFrame 不是用于缓慢的维度检测,而是恰恰相反:它平滑所有由基于真实事件的调整大小传感器触发的极端数量的事件,以节省 CPU 时间。请参阅github.com/marcj/css-element-queries/blob/master/src/...
2021-04-01 23:24:47
@Orwellophile 你显然什么都不明白。在您不知道内部如何工作的情况下,停止拒绝投票。再次: css-element-query: 使用每次尺寸更改时触发的真实调整大小事件。由于您会收到太多事件(例如拖放),它添加了 requestAnimationFrame 检查一个简单的布尔变量,以将这些触发的事件平滑到 1/帧。jquery 插件:使用 setTimeout 始终检查 DOM 布局道具(clientHeight 等),其中每次检查都很慢,但需要经常检查以具有相同的功能。
2021-04-08 23:24:47

从长远来看,您将能够使用ResizeObserver.

new ResizeObserver(callback).observe(element);

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

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

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

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
  });
};
@nkron,不幸的是,如果您使用CSS3 resize,则在用户手动调整大小时可能会发生调整大小。无法捕获此事件。
2021-03-16 23:24:47
不幸的是,MutationObserver 似乎无法检测到 Shadow DOM 中的变化。
2021-03-24 23:24:47
@trusktr 我目前没有 MCVE,但基本上任何可以由于某些用户输入而改变其大小的 Shadow DOM 元素都足以触发此问题。例如,单击时会扩展一些附加信息的框。请注意,我正在观察页面,而不是单个元素,因为我想在页面大小增加时自动向下滚动,无论出于何种原因。Shadow DOM 元素扩展只是页面变长的众多可能原因之一。
2021-04-03 23:24:47
@Ajedi32 是的,但您可以在 ShadowDOM 中使用 MutationObserver。我的意思是body,您可以直接观看一个元素,而不是像本例中那样观看。这实际上比观看整个身体更有性能和效率。
2021-04-04 23:24:47
@Ajedi32 好吧,唯一的问题是,如果 Shadow DOM 树关闭,那么您将无法访问内部结构,但我认为这通常不是您需要做的事情,如果您需要观察像这样的封闭树那么设计中可能存在问题。理想情况下,您应该只需要观察您自己可以访问的元素。需要您观察其内部大小的 Shadow-DOM 组件可能设计不当。你有具体的例子吗?如果是这样,也许我可以帮助提出一个解决方案(因为我也对它感兴趣,但还没有例子)。
2021-04-09 23:24:47

ResizeSensor.js是一个巨大的图书馆的一部分,但我减少了它的功能,以

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 所做的。
2021-03-11 23:24:47
上面的解决方案/代码不会检测所有调整大小事件(例如,如果容器调整为固定大小,则不会检测到子事件的调整大小。请参阅jsfiddle.net/8md2rfsy/1)。接受的答案有效(取消注释相应的行)。
2021-03-11 23:24:47
我很困惑“让 zIndex = parseInt(getComputedStyle(element));” 有效的?我假设你的意思是:“让 zIndex = parseInt(getComputedStyle(element).zIndex);
2021-03-14 23:24:47
这个表达中缺少一些东西 parseInt( getComputedStyle(element) )
2021-03-17 23:24:47
感谢您压缩它。我要试试看:)
2021-03-24 23:24:47

您必须resizewindow对象绑定事件,而不是在通用 html 元素上。

然后你可以使用这个:

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

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

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

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

这个答案还不够好。可能会在没有调整任何窗口大小的情况下发生大小更改。根本。
2021-03-14 23:24:47
@anu 不正确,您可以通过 javascript 进行例如 DOM 修改,导致 CSS 应用于新结构,从而导致不同的布局 - 每个容器的大小。
2021-03-18 23:24:47
例如,当您有一个拆分器元素或只是将一些文本或其他内容附加到元素时。
2021-03-21 23:24:47