概述
ResizeObserver 是一个 JavaScript API,用于监视元素的大小变化。它可以观察一个或多个 DOM 元素,以便在元素的大小或形状发生变化时触发回调函数。ResizeObserver 是为了更有效地处理元素尺寸变化而引入的,特别适用于响应式设计和自适应布局。
简化尺寸观察:ResizeObserver 提供了一种简单而强大的方法来监视元素的大小变化,而无需使用传统的事件监听器和轮询。
观察多个元素:你可以同时观察多个 DOM 元素,当这些元素的尺寸发生变化时,ResizeObserver 会在每个元素上触发回调函数。
异步回调:ResizeObserver 的回调是异步执行的,这意味着它会在浏览器准备好更新时触发,而不会引发性能问题。
支持容器查询:容器查询是一种在元素的尺寸变化时,根据容器的尺寸来调整元素的布局。ResizeObserver 可以用于实现容器查询的功能。
适应响应式设计:ResizeObserver 对于响应式设计非常有用,可以根据元素的尺寸变化来调整布局,以适应不同的屏幕尺寸和设备。
适用于自定义组件:你可以将 ResizeObserver 集成到自定义组件中,以便在组件内监视子元素的大小变化。
兼容性分析
完全不兼容ie浏览器,主流浏览器只兼容高版本,基本上2018年以前的浏览器都不兼容,部分浏览器甚至2020年以前都不兼容。
优点分析
而ResizeObserver API就可以帮助我们:监听一个DOM节点的变化,这种变化包括但不仅限于:
1.某个节点的出现和隐藏
2.某个节点的大小变化
ResizeObserver避免了在自身回调中调整大小,从而触发的无限回调和循环依赖。它仅通过在后续帧中处理DOM中更深层次的元素来实现这一点。如果(浏览器)遵循规范,只会在绘制前或布局后触发调用。
可以代替
window.onresize = function() {
// SomeJavaScriptCode
};
用法
ResizeObserver是个构造函数。在使用new关键字调用构造函数,返回实例对象时,需要传入一个回调函数,这个回调用于监听实例对象某个DOM节点的变化
<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: 'ResizeObsever',
mounted() {
const myObserver = new ResizeObserver((entries) => {
entries.forEach((entry) => {
console.log('被监听元素content的宽高及位置', entry.contentRect)
// bottom: 700 指top + height的值
// height: 600 指元素本身的高度,不包含padding,border值
// left: 100 指padding-left的值
// right: 1143 指left + width的值
// top: 100 指padidng-top的值
// width: 1043 指元素本身的宽度,不包含padding,border值
// x: 100
// y: 100
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)
}
}
</script>
<style>
.resize-warpper {
background: skyblue;
}
.resize-element {
width: calc(100% - 700px);
background: #ff2d52;
height: 600px;
padding: 100px;
margin: 150px;
border: 100px solid green;
}
.resize-content {
width: 100%;
height: 100%;
background: yellow;
}
</style>
实例对象myObserver方法除了有observe方法之外,还有disconnect方法和unobserve方法。
disconnect()
取消和结束目标对象上所有对 Element或 SVGElement 观察。
setTimeout(() => {
resizeObserver.disconnect(this.$refs.wrapper);
}, 4000);
vue2.0中在beforeDestroy 中
beforeDestroy() {
resizeObserver.disconnect(this.$refs.wrapper);
},
vue3.0中在beforeUnmount
beforeUnmount() {
resizeObserver.disconnect(this.$refs.wrapper);
}
reactHook在useEffect返回的回调中
useEffect(() => {
return () => {
resizeObserver.disconnect(this.$refs.wrapper);
}
},[])
react 在 componentWillUnmount()中
componentWillUnmount() {
resizeObserver.disconnect(this.$refs.wrapper);
}
unobserve()
结束观察指定的Element或 SVGElement。具体用法与disconnect一致。
节流使用
最后,在使用ResizeObserver API的时候,在每次触发元素的大小变化时,会在1s内触发回调蛮多次的。如果想进一步优化性能,可以加上throttle节流函数处理
const throttle = (fun,delay) => {
let timer = null;
return function() {
const args = arguments
if(!timer) {
timer = setTimeout(() => {
timer = null
}, delay)
fun(args )
}
}
}
const myObserver = new ResizeObserver(throttle(entries => {
entries.forEach(entry => {
console.log('大小位置 contentRect', entry.contentRect)
console.log('监听的DOM target', entry.target)
})
}), 500)
myObserver.observe(document.body)