ResizeObserver介绍
- ResizeObserver 是一个 JavaScript API,用于监视元素的大小变化。它可以观察一个或多个元素,以便在元素的大小或形状发生变化时触发回调函数。ResizeObserver 是为了更有效地处理元素尺寸变化而引入的,特别适用于响应式设计和自适应布局。
- 简化尺寸观察:ResizeObserver 提供了一种简单而强大的方法来监视元素的大小变化,而无需使用传统的事件监听器和轮询。
- 观察多个元素:你可以同时观察多个 DOM 元素,当这些元素的尺寸发生变化时,ResizeObserver 会在每个元素上触发。
- 异步回调:ResizeObserver 的回调是异步执行的,这意味着它会在浏览器准备好更新时触发,而不会引发性能问题。
- 支持容器查询:容器查询是一种在元素的尺寸变化时,根据容器的尺寸来调整元素的布局。ResizeObserver 可以用于实现容器查询的功能。
ResizeObserver API就可以帮助我们:监听一个DOM节点的变化,这种变化如:
- 某个节点的出现和隐藏。
- 某个节点的大小变化。
ResizeObserver避免了在自身回调中调整大小,从而触发的无限回调和循环依赖。它仅通过在后续帧中处理DOM中更深层次的元素来实现这一点。如果(浏览器)遵循规范,只会在绘制前或布局后触发调用。
可以代替:
window.onresize = function() {
// SomeJavaScriptCode
};
具体用法
vue2
<template>
<div class="resize-warpper">
margin
<div class="resize-element" ref="wrapper">
padding
<div class="resize-content">content</div>
</div>
margin
</div>
</template>
<script>
export default {
name: 'ResizeObserver',
data() {
return {
}
},
mounted() {
const myObserver = new ResizeObserver((entries) => {
entries.forEach(entry => {
console.log('真实dom元素',entry.target)
console.log('被监听元素content的宽高及位置', entry.contentRect)
// bottom: 指top + height的值
// height: 指元素本身的高度,不包含padding,border值
// left: 指padding-left的值
// right: 指left + width的值
// top: 指padidng-top的值
// width: 指元素本身的宽度,不包含padding,border值
// x: 元素内容区域左边缘相对于视口或包含块的水平偏移量。
// y: 元素内容区域顶边相对于视口或包含块的垂直偏移量。
console.log('被监听元素的宽高', entry.borderBoxSize)
// blockSize: 1000
// inlineSize: 1443
console.log('被监听元素content部分的宽高', entry.contentBoxSize)
// blockSize: 600
// inlineSize: 1043
console.log('被监听元素', entry.target)
})
})
myObserver .observe(this.$refs.wrapper)
},
methods: {
}
}
</script>
<style lang="less" scoped>
</style>
其它实例方法
ResizeObserver 接口的 disconnect() 方法取消所有的对 Element 或 SVGElement 目标的监听。 ResizeObserver 接口的 unobserve() 方法结束对指定的 Element 或 SVGElement 的监听。 在vue2中,可以:
beforeDestroy() {
resizeObserver.disconnect(this.$refs.wrapper);
}
组件源码
import ResizeObserver from 'resize-observer-polyfill'; // 为了更好的兼容性
const resizeHandler = function(entries) {
for (let entry of entries) {
const listeners = entry.target.__resizeListeners__ || [];
if (listeners.length) {
listeners.forEach(fn => {
fn();
});
}
}
};
/* istanbul ignore next */
export const addResizeListener = function(element, fn) {
if (isServer) return;
if (!element.__resizeListeners__) {
element.__resizeListeners__ = [];
element.__ro__ = new ResizeObserver(debounce(16, resizeHandler));
element.__ro__.observe(element);
}
element.__resizeListeners__.push(fn);
};
/* istanbul ignore next */
export const removeResizeListener = function(element, fn) {
if (!element || !element.__resizeListeners__) return;
element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
if (!element.__resizeListeners__.length) {
element.__ro__.disconnect();
}
};