Vue 3与ResizeObserver API:监听元素尺寸变化

2025-04发布7次浏览

Vue 3 是一个现代化的前端框架,提供了强大的响应式系统和组件化开发能力。结合现代浏览器提供的 ResizeObserver API,我们可以轻松监听 DOM 元素的尺寸变化,并在 Vue 3 的响应式系统中进行动态更新。本文将详细介绍如何在 Vue 3 中使用 ResizeObserver API 来监听元素尺寸变化,包括实现步骤、代码示例以及相关优化技巧。


一、ResizeObserver API 简介

ResizeObserver 是一种现代浏览器 API,用于监听 DOM 元素的尺寸变化(如宽度、高度)。与传统的 resize 事件不同,ResizeObserver 只关注特定元素的尺寸变化,因此性能更高且更加精确。

核心方法

  • new ResizeObserver(callback):创建一个新的 ResizeObserver 实例。
  • observe(target):开始观察指定的目标元素。
  • unobserve(target):停止观察指定的目标元素。
  • disconnect():停止观察所有目标元素。

回调函数参数

callback 函数会在目标元素的尺寸发生变化时被触发,其参数为一个数组,每个元素包含以下信息:

  • contentRect:一个 DOMRectReadOnly 对象,表示目标元素的内容区域(包括宽度和高度)。

二、在 Vue 3 中集成 ResizeObserver

Vue 3 提供了 Composition API 和 Options API,我们可以通过这两种方式来集成 ResizeObserver。下面分别介绍两种实现方式。

1. 使用 Composition API

Composition API 是 Vue 3 推荐的开发方式,适合逻辑复用和模块化开发。以下是具体实现步骤:

步骤 1:定义自定义 Hook

我们可以封装一个通用的自定义 Hook 来处理 ResizeObserver 的逻辑。

import { ref, onMounted, onUnmounted } from 'vue';

export function useElementSize() {
  const width = ref(0);
  const height = ref(0);

  let observer;

  const observeElement = (el) => {
    if (!el) return;

    observer = new ResizeObserver((entries) => {
      for (const entry of entries) {
        width.value = entry.contentRect.width;
        height.value = entry.contentRect.height;
      }
    });

    observer.observe(el);
  };

  const stopObserving = () => {
    if (observer) {
      observer.disconnect();
    }
  };

  return {
    width,
    height,
    observeElement,
    stopObserving,
  };
}
步骤 2:在组件中使用 Hook

通过 useElementSize Hook,我们可以轻松监听某个 DOM 元素的尺寸变化。

<template>
  <div ref="targetElement" class="box">
    宽度: {{ width }}px<br />
    高度: {{ height }}px
  </div>
</template>

<script>
import { ref, onMounted, onUnmounted } from 'vue';
import { useElementSize } from './useElementSize';

export default {
  setup() {
    const targetElement = ref(null);
    const { width, height, observeElement, stopObserving } = useElementSize();

    onMounted(() => {
      if (targetElement.value) {
        observeElement(targetElement.value);
      }
    });

    onUnmounted(() => {
      stopObserving();
    });

    return {
      targetElement,
      width,
      height,
    };
  },
};
</script>

<style>
.box {
  width: 200px;
  height: 100px;
  background-color: lightblue;
  resize: both;
  overflow: auto;
}
</style>

2. 使用 Options API

如果你更熟悉 Options API,也可以通过 mountedbeforeDestroy 生命周期钩子来实现类似的功能。

<template>
  <div ref="targetElement" class="box">
    宽度: {{ width }}px<br />
    高度: {{ height }}px
  </div>
</template>

<script>
export default {
  data() {
    return {
      width: 0,
      height: 0,
    };
  },
  mounted() {
    this.observer = new ResizeObserver((entries) => {
      for (const entry of entries) {
        this.width = entry.contentRect.width;
        this.height = entry.contentRect.height;
      }
    });

    if (this.$refs.targetElement) {
      this.observer.observe(this.$refs.targetElement);
    }
  },
  beforeDestroy() {
    if (this.observer) {
      this.observer.disconnect();
    }
  },
};
</script>

<style>
.box {
  width: 200px;
  height: 100px;
  background-color: lightblue;
  resize: both;
  overflow: auto;
}
</style>

三、性能优化与注意事项

  1. 避免频繁触发回调
    如果目标元素的尺寸变化非常频繁(例如动画或拖拽操作),可能会导致性能问题。可以结合防抖(debounce)或节流(throttle)技术来优化。

  2. 清理观察器
    在组件卸载时务必调用 disconnect 方法,否则会导致内存泄漏。

  3. 兼容性
    虽然大多数现代浏览器都支持 ResizeObserver,但在一些老旧浏览器中可能不兼容。可以考虑使用 resize-observer-polyfill 进行 polyfill。


四、总结

通过 Vue 3 的响应式系统和 ResizeObserver API 的结合,我们可以轻松实现对 DOM 元素尺寸变化的监听。无论是使用 Composition API 还是 Options API,都可以根据实际需求选择合适的方式。此外,为了提升性能和兼容性,还需要注意清理观察器以及使用 polyfill。