4种动态监听DOM元素高度变化的方法

412 阅读3分钟

大家好,我是前端架构师,关注微信公众号【程序员大卫】,免费领取精品前端资料。

背景

在前端开发中,监听DOM元素的高度变化有时候是一个常见需求,尤其是在做响应式设计或需要根据内容变化调整布局时。

一. ResizeObserver

ResizeObserver 是现代浏览器提供的一种监听元素尺寸变化的 API。它可以监听任意元素的大小变化,并在变化时触发回调函数,适合处理 DOM 元素高度变化的情况。

  • ResizeObserver 会监听目标元素的大小变化,并返回一个 entries 数组,其中每一项代表一个被观察的元素。
  • entry.contentRect 是一个包含元素尺寸信息的矩形对象,height 属性即为元素的高度。

示例代码

// 选择你想要监听的 DOM 元素
const targetElement = document.querySelector('.target');

// 创建 ResizeObserver 实例,并传入回调函数
const resizeObserver = new ResizeObserver(entries => {
    // entries 是一个包含被监听元素的数组
    entries.forEach(entry => {
        // 获取目标元素的当前高度
        const height = entry.contentRect.height;
        console.log('元素的当前高度:', height);
    });
});

// 开始监听目标元素的尺寸变化
resizeObserver.observe(targetElement);

二. 原生手写 Iframe 监听

通过嵌入一个隐藏的 iframe 元素,可以监听 iframe 元素的 resize 事件来间接判断容器的高度。

  • 这个方法通过将一个隐藏的 iframe 嵌套到目标容器内,利用 iframe 的 resize 事件来检测容器的高度变化。
  • 由于 iframeresize 事件会在容器的尺寸发生变化时触发,因此我们可以在事件回调中获取容器的最新高度。
  • 此方法的兼容性更广,可以支持老旧浏览器,如 IE 浏览器。

示例代码

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>动态监听DOM元素高度变化 - iframe 示例</title>
    <style>
        .container {
            width: 100%;
            height: 200px; /* 初始高度 */
            position: relative;
            border: 1px solid #ccc;
        }
        .resize-iframe {
            width: 100%;
            height: 100%;
            border: none;
            position: absolute;
            top: 0;
            left: 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <iframe class="resize-iframe" src="about:blank"></iframe>
    </div>

    <script>
        const container = document.querySelector('.container');
        const iframe = document.querySelector('.resize-iframe');

        // 监听 iframe 的 resize 事件
        iframe.contentWindow.addEventListener('resize', function () {
            // 获取容器的当前高度
            console.log('容器的当前高度:', container.offsetHeight);
        });

        // 为了演示,在容器的高度变化时触发 resize 事件
        setInterval(() => {
            container.style.height = Math.random() * 500 + 'px';  // 随机调整容器高度
        }, 2000);  // 每2秒调整一次高度
    </script>
</body>
</html>

三. element-resize-detector

它的原理是在目标元素内部插入一个不可见的 object,并监听 resize 事件来检测父容器尺寸的变化。

<div id="target" style="position: relative;">
  <object type="text/html" data="about:blank" 
          style="display: block; position: absolute; top: 0; left: 0; 
                 height: 100%; width: 100%; overflow: hidden; 
                 pointer-events: none; z-index: -1;">
  </object>
  </div>
objectElement.contentDocument.defaultView.addEventListener('resize', () => {
   // 因为 object 尺寸变了,说明父容器尺寸也变了
   triggerCallback();
});

安装

npm install element-resize-detector

使用方法

var elementResizeDetectorMaker = require("element-resize-detector");

var erd = elementResizeDetectorMaker();

var element = document.getElementById("my-element");

erd.listenTo(element, function(element) {
  var width = element.offsetWidth;
  var height = element.offsetHeight;
  console.log("尺寸变化: " + width + "x" + height);
});

四. resize-observer-polyfill

它的原理是基于 MutationObserver 的 API 来观察 DOM 的变化,从而监听尺寸变化。

安装

npm install resize-observer-polyfill --save-dev

使用方法

在你的代码中引入并使用它。它的行为会尽可能模拟原生 API。

import ResizeObserver from 'resize-observer-polyfill';

// 1. 获取你要监听的 DOM 元素
const myElement = document.querySelector('#my-element');

// 2. 创建观察者实例
const ro = new ResizeObserver((entries, observer) => {
    for (const entry of entries) {
        const { left, top, width, height } = entry.contentRect;
        console.log('尺寸发生变化:', width, height);
        // 这里可以执行你的逻辑,例如重新渲染图表等
    }
});

// 3. 开始监听
ro.observe(myElement);

// 4. 停止监听
// ro.disconnect();

缺点

  • CSS 伪类导致的尺寸变化,它不能监听。比如 .box:hover {width: 200px;}
  • 父级容器变化导致的“被动”缩放,它不能监听
  • 外部资源加载 (图片/字体),它不能监听。

总结

  • 对于现在浏览器,首选第1种方法 ResizeObserver。
  • 对于老浏览器选择第2和第3种方法。
  • 不推荐第4种方法。