实现跨浏览器支持的 ResizeObserver Polyfill
使用自定义 ResizeObserver
在 Vue 和 React 中监听元素尺寸变化
在前端开发中,监听元素尺寸变化是一个常见的需求。虽然现代浏览器提供了 ResizeObserver
API,但是在一些旧版本的浏览器中可能不支持。本文将介绍如何实现一个自定义的 ResizeObserver
,并在 Vue 和 React 中使用它来监听元素的尺寸变化。 2
什么是 ResizeObserver?
ResizeObserver
是一种新的浏览器 API,用于监听元素内容矩形的变化。当元素的尺寸(宽度或高度)发生变化时,会触发回调函数。ResizeObserver
是响应式设计和复杂布局的理想选择。
自定义 ResizeObserver 的实现
以下是一个简单的 ResizeObserver
实现,它使用 window.resize
事件来检查元素的尺寸变化:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
window.ResizeObserver = class {
constructor(callback) {
this.observables = [];
this.boundCheck = this.check.bind(this);
this.callback = callback;
}
observe(element) {
if (!this.observables.some(observable => observable.element === element)) {
this.observables.push({ element, width: element.clientWidth, height: element.clientHeight });
}
window.addEventListener('resize', this.boundCheck);
this.boundCheck();
}
unobserve(element) {
this.observables = this.observables.filter(observable => observable.element !== element);
if (!this.observables.length) {
window.removeEventListener('resize', this.boundCheck);
}
}
disconnect() {
this.observables = [];
window.removeEventListener('resize', this.boundCheck);
}
check() {
this.observables.forEach(observable => {
const { element } = observable;
const newWidth = element.clientWidth;
const newHeight = element.clientHeight;
if (newWidth !== observable.width || newHeight !== observable.height) {
observable.width = newWidth;
observable.height = newHeight;
this.callback([{ target: element }]);
}
});
}
};
代码解释:
构造函数:
constructor(callback)
接受一个回调函数作为参数,并初始化observables
数组、绑定的check
方法和回调函数。observe(element):该方法用于观察指定元素的尺寸变化。如果该元素尚未被观察,则将其加入
observables
数组,并添加resize
事件监听器。unobserve(element):该方法用于停止观察指定元素的尺寸变化,并从
observables
数组中移除。如果没有需要观察的元素,则移除resize
事件监听器。disconnect():该方法用于停止观察所有元素的尺寸变化,并移除所有
resize
事件监听器。check():该方法遍历所有被观察的元素,检查它们的尺寸是否发生变化。如果发生变化,则更新尺寸并触发回调函数。
在 Vue 中使用自定义 ResizeObserver
下面是一个在 Vue 组件中使用自定义 ResizeObserver
的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<template>
<div ref="resizeElement" class="resize-element">
<p>Resize the window to see changes</p>
</div>
</template>
<script>
export default {
name: 'ResizeObserverExample',
data() {
return {
resizeObserver: null,
elementSize: { width: 0, height: 0 }
};
},
mounted() {
this.resizeObserver = new ResizeObserver(entries => {
for (let entry of entries) {
const { width, height } = entry.target.getBoundingClientRect();
this.elementSize.width = width;
this.elementSize.height = height;
console.log('Element resized:', this.elementSize);
}
});
this.resizeObserver.observe(this.$refs.resizeElement);
},
beforeDestroy() {
if (this.resizeObserver) {
this.resizeObserver.disconnect();
}
}
};
</script>
<style>
.resize-element {
width: 100%;
height: 200px;
background-color: #f0f0f0;
}
</style>
代码解释:
data()
:初始化组件的状态,包含resizeObserver
和elementSize
。mounted()
:在组件挂载后,创建ResizeObserver
实例并开始观察resizeElement
元素的尺寸变化。beforeDestroy()
:在组件销毁前,断开ResizeObserver
的连接,停止观察。resizeElement
:一个简单的div
元素,当窗口尺寸变化时,其宽度和高度会被更新。
在 React 中使用自定义 ResizeObserver
下面是一个在 React 组件中使用自定义 ResizeObserver
的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import React, { useRef, useEffect, useState } from 'react';
const ResizeObserverExample = () => {
const resizeRef = useRef(null);
const [size, setSize] = useState({ width: 0, height: 0 });
useEffect(() => {
const resizeObserver = new ResizeObserver(entries => {
for (let entry of entries) {
const { width, height } = entry.target.getBoundingClientRect();
setSize({ width, height });
console.log('Element resized:', { width, height });
}
});
if (resizeRef.current) {
resizeObserver.observe(resizeRef.current);
}
return () => {
if (resizeObserver) {
resizeObserver.disconnect();
}
};
}, []);
return (
<div ref={resizeRef} style={{ width: '100%', height: '200px', backgroundColor: '#f0f0f0' }}>
<p>Resize the window to see changes</p>
<p>Width: {size.width}px, Height: {size.height}px</p>
</div>
);
};
export default ResizeObserverExample;
代码解释:
useRef
:创建一个ref
,用于引用需要观察的 DOM 元素。useState
:定义状态size
,用于存储元素的宽度和高度。useEffect
:在组件挂载后,创建ResizeObserver
实例并开始观察resizeRef
元素的尺寸变化。在组件卸载时,断开ResizeObserver
的连接,停止观察。resizeRef
:一个div
元素,当窗口尺寸变化时,其宽度和高度会被更新。
总结
通过自定义 ResizeObserver
,我们可以在 Vue 和 React 组件中轻松监听元素的尺寸变化。无论是响应式设计还是复杂布局,这种方法都非常实用。如果你的项目需要兼容旧版本的浏览器,不妨尝试一下这种自定义实现。
希望这篇文章对你有所帮助!欢迎在评论区分享你的使用经验和建议。