ResizeObserver API是一个新的JavaScript API,与允许我们去监听某个元素的宽高变化。
完全不兼容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方法。
取消和结束目标对象上所有对 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);
}
结束观察指定的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)