ResizeObserver在项目中的应用

2024-09-14 10:31:06 浏览数 (2)

ResizeObserver在项目中的应用

ResizeObserver是一个用于监听元素尺寸变化的 JavaScript API。它可以在不依赖轮询或事件冒泡的情况下,高效地检测元素尺寸的变化。

ResizeObserverResizeObserver
代码语言:html复制
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>ResizeObserver Example</title>
  <style>
    #observedElement {
      background-color: #f0f0f0;
      padding: 10px;
      border: 1px solid #ccc;
      
    }
  </style>
</head>

<body>
  <div id="observedElement">This is an observed element.</div>

  <div class="info"></div>
  <script>
    const observedElement = document.getElementById('observedElement');
    const info = document.querySelector('.info');
    const resizeObserver = new ResizeObserver(entries => {
      for (const entry of entries) {
        console.log(`Element's new size: ${entry.contentRect.width} x ${entry.contentRect.height}`, entry.target.textContent);
        info.textContent = `Element's new size: ${entry.contentRect.width} x ${entry.contentRect.height}`;
      }
    });

    resizeObserver.observe(observedElement);
  </script>
</body>

</html>

上述示例中:

  1. 首先获取要观察的元素。
  2. 创建一个ResizeObserver实例,并传入一个回调函数。当观察的元素尺寸发生变化时,回调函数会被触发,并且会接收到一个包含观察元素信息的entries数组。
  3. 在回调函数中,遍历entries数组,通过entry.contentRect可以获取到元素的新尺寸信息。
  4. 最后,使用observe方法开始观察指定的元素。

ResizeObserver在响应式布局、动态调整元素大小等场景中非常有用,可以避免频繁的轮询操作,提高性能。

ResizeObserver的一些应用

一、响应式图片布局

当窗口大小变化时,根据容器的尺寸动态调整图片的大小,以确保图片在不同屏幕尺寸下都能良好显示。

代码语言:html复制
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Responsive Image with ResizeObserver</title>
  <style>
   .image-container {
      width: 50%;
      border: 1px solid #ccc;
    }

    img {
      width: 100%;
      height: auto;
    }
  </style>
</head>

<body>
  <div class="image-container">
    <img src="https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/48950506dec046379133b3e851f4eb87~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5LiA6LW36YeN5a2m5YmN56uv:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMTQwMzg1MTA2NzkxOTExIn0=&rk3s=f64ab15b&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1726885385&x-orig-sign=n8KsLmSdp6fAD/QDT9hwzQ1oYf4=" alt="Image">
  </div>
  <div class="imageText"></div>

  <script>
    const imageContainer = document.querySelector('.image-container');
    const img = document.querySelector('img');
    const imageText = document.querySelector('.imageText');
    const resizeObserver = new ResizeObserver(entries => {
      for (const entry of entries) {
        const newWidth = entry.contentRect.width;
        img.style.width = newWidth   'px';
        imageText.textContent = `Image width: ${newWidth}px`;
      }
    });

    resizeObserver.observe(imageContainer);
  </script>
</body>

</html>

二、自适应导航栏

根据窗口宽度调整导航栏的样式,例如在小屏幕下转换为移动端菜单样式。

大屏

小屏

代码语言:html复制
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Adaptive Navbar with ResizeObserver</title>
  <style>
    nav {
      display: flex;
      justify-content: space-between;
      padding: 10px;
    }

    @media (max-width: 768px) {
      nav {
        flex-direction: column;
      }
    }
  </style>
</head>

<body>
  <nav>
    <a href="#">Home</a>
    <a href="#">About</a>
    <a href="#">Contact</a>
  </nav>

  <script>
    const nav = document.querySelector('nav');

    const resizeObserver = new ResizeObserver(entries => {
      for (const entry of entries) {
        if (entry.contentRect.width <= 768) {
          nav.classList.add('mobile-nav');
        } else {
          nav.classList.remove('mobile-nav');
        }
      }
    });

    resizeObserver.observe(nav);
  </script>
</body>

</html>

三、动态布局调整

在复杂的页面布局中,根据某个关键元素的尺寸变化,动态调整其他元素的位置和大小。

代码语言:html复制
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Dynamic Layout with ResizeObserver</title>
  <style>
 
   .main-content {
      display: flex;
      background-color: #ccc;
      padding: 20px;
    }

   .sidebar {
      width: 200px;
      background-color: #f0f0f0;
      padding: 10px;
    }

   .content {
      flex: 1;
      background-color: #999;
    }
  </style>
</head>

<body>
  <div class="main-content">
    <div class="sidebar"></div>
    <div class="content"></div>
  </div>

  <script>
    const mainContent = document.querySelector('.main-content');
    const sidebar = document.querySelector('.sidebar');
    const content = document.querySelector('.content');

    const resizeObserver = new ResizeObserver(entries => {
      for (const entry of entries) {
        const newWidth = entry.contentRect.width;
        sidebar.style.width = newWidth > 800? 200 : 100   'px';
        content.style.width = newWidth - sidebar.offsetWidth   'px';
      }
    });

    resizeObserver.observe(mainContent);
  </script>
</body>

</html>

ResizeObserver虽然很有用,但也存在一些局限性:

一、浏览器兼容性

并非所有浏览器都完全支持ResizeObserver。一些较旧的浏览器可能不支持这个 API,这就需要使用垫片(polyfill)或者考虑其他替代方案来确保在不同浏览器环境下的功能一致性。例如,在一些旧版本的 Internet Explorer 中无法使用。

通过以下几种方式解决ResizeObserver的浏览器兼容性问题:

a. 使用 Polyfill

可以使用ResizeObserver的 polyfill 库,例如resize-observer-polyfill

  1. 安装:
代码语言:bash复制
   npm install resize-observer-polyfill
  1. 使用:
代码语言:javascript复制
   import ResizeObserver from 'resize-observer-polyfill';

   const observer = new ResizeObserver(entries => {
     // 处理尺寸变化
   });

   observer.observe(document.getElementById('myElement'));
b、特征检测和备用方案

1.进行特征检测:

代码语言:javascript复制
   const isResizeObserverSupported = typeof ResizeObserver!== 'undefined';

2.如果不支持ResizeObserver,可以使用其他方式来模拟尺寸变化的监测,比如使用定时器进行轮询检测元素尺寸变化,但这种方式性能相对较差。

代码语言:javascript复制
   let elementWidth;
   let elementHeight;

   const checkSize = () => {
     const element = document.getElementById('myElement');
     const newWidth = element.offsetWidth;
     const newHeight = element.offsetHeight;
     if (newWidth!== elementWidth || newHeight!== elementHeight) {
       elementWidth = newWidth;
       elementHeight = newHeight;
       // 处理尺寸变化
     }
   };

   setInterval(checkSize, 100);

二、性能考虑

虽然ResizeObserver相比传统的轮询或事件监听方式在性能上有很大提升,但如果同时观察大量元素,或者在复杂的布局场景下频繁触发尺寸变化,仍然可能会对性能产生一定影响。特别是在一些资源受限的设备上,可能会出现卡顿现象。

三、观察对象限制

只能观察 DOM 元素的尺寸变化,对于其他类型的对象(如 SVG 元素、Canvas 元素等非传统 DOM 元素)的尺寸变化无法直接观察,可能需要通过间接的方式或者其他特定的技术来实现对这些对象尺寸变化的监测。

四、复杂布局场景下的不确定性

在非常复杂的布局场景中,尤其是涉及到多个嵌套的、具有复杂 CSS 属性和定位的元素时,ResizeObserver可能无法准确地反映出元素的实际可视尺寸变化。例如,当元素的尺寸受到父元素的transformfilter等属性影响时,ResizeObserver可能无法准确捕捉到这些变化对元素最终尺寸的影响。

MutationObserverResizeObserver的区别

一、监测目标

  • MutationObserver:主要用于观察 DOM 节点的变化,包括节点的添加、删除、属性的修改、文本内容的变化等。它可以监听特定 DOM 元素及其子树的这些变化情况。
  • ResizeObserver:专门用于监听 DOM 元素的尺寸变化,即元素的宽度、高度、边框等尺寸属性的改变。

二、触发条件

  • MutationObserver:当被观察的 DOM 元素或其子树发生了指定类型的变化时触发回调函数。例如,当一个元素的属性被修改、子元素被添加或删除时,MutationObserver会通知开发者。
  • ResizeObserver:仅在被观察元素的尺寸发生变化时触发回调。这个尺寸变化可以是由于窗口大小调整、CSS 样式的改变导致元素大小改变等原因引起的。

三、使用场景

MutationObserver

  • 适用于需要实时响应 DOM 结构变化的场景。比如,当一个页面上的某些元素可能会动态地添加或删除,并且需要根据这些变化进行相应的处理时,可以使用MutationObserver
  • 监测表单元素的值变化,以便在用户输入时实时进行数据验证或更新其他相关部分的界面。

ResizeObserver

  • 在响应式设计中,当需要根据元素尺寸的变化来调整布局、重新绘制图形或调整其他与尺寸相关的属性时非常有用。
  • 例如,当一个容器元素的大小改变时,自动调整内部的图像、图表或其他内容的大小以适应新的空间。

四、性能影响

两者在使用不当的情况下都可能对性能产生一定影响,但影响方式略有不同:

  • MutationObserver:如果被观察的 DOM 结构频繁发生变化,或者回调函数中执行了复杂的操作,可能会导致性能下降。特别是在处理大量动态变化的 DOM 时,需要注意优化回调函数以避免性能问题。
  • ResizeObserver:如果页面中有很多元素被观察,并且尺寸变化频繁发生,也可能会影响性能。但是,由于它只针对尺寸变化进行触发,相对来说在一些场景下可能比MutationObserver更加高效,因为它不会对其他无关的 DOM 变化做出响应。

腾讯技术创作特训营s9

「学习NestJS的第一个接口(一)」

「学习NestJS开发小程序后台(一)」

「学习NestJS开发小程序后台(二)图片鉴黄」

0 人点赞