window有resize事件,但某些时候我们想监听某个div的resize,这个时候可以使用 ResizeObserver。
以下出自 mdn 文档:
ResizeObserver
接口监视 Element
内容盒或边框盒或者 SVGElement
边界尺寸的变化。
备注: 内容盒是盒模型放置内容的部分,这意味着边框盒减去内边距和边框的宽度就是内容盒。边框盒包含内容、内边距和边框。有关进一步阐述,参见盒模型。
ResizeObserver
避免了通过回调函数调整大小时,通常创建的无限回调循环和循环依赖项。它只能通过在后续的帧中处理 DOM 中更深层次的元素来做到这一点。如果它的实现遵循规范,则应在绘制前和布局后调用 resize 事件。
详细文档请查阅 ResizeObserver。
使用分三步
// 1.指定resize事件
let resizeFn = (entries,observer)=>{// 注意这里有参数,包含一些位置,盒子大小信息,对 ResizeObserver 自身的引用
console.log('div宽高变化将触发此方法')
}
let resizeObserver = new ResizeObserver(resizeFn) // 注意初始会调用一次 resizeFn
// 2.指定该resize事件的触发dom
let resizeBox = document.getElementById('myDom')
resizeObserver.observe(resizeBox);
// 3.结束对指定dom的监听。
resizeObserver.unobserve(resizeBox)
ResizeObserver 实例化函数参数文档,也就是上面的 entries,observer - 看这里,我目前感觉用不用都可以,因为也可以用其他方式获取这些信息。
使用案例
<template>
<div ref="resizeDivRefDom" class="resize-div">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'resizeDiv',
props: {
// 防抖时间
t: {
type: Number,
default: 50
},
// 初始第一次是否触发 resize 事件
firstTrigger: {
type: Boolean,
default: true
}
},
data() {
return {
resizeObserver: null,
tickTimer: null,
firstTime: true, // 标记是否初始渲染
domWh: { // 当前 dom 信息
width: 0,
height: 0
}
}
},
methods: {
// 根据需求,可以获取任意信息
getDomInfo(dom) {
return {
width: dom.clientWidth,
height: dom.clientHeight
}
},
emitEvent() {
// console.log('resizeDiv resize...')
let resizeBox = this.$refs['resizeDivRefDom']
let oldDomInfo = this.domWh
let newDomInfo = this.domWh = this.getDomInfo(resizeBox)
this.$emit('resize', {
resizeBox, // 当前 resize 的dom信息
oldDomInfo, // resize 前的宽高信息
newDomInfo // resize 后的宽高信息
})
},
event_resize() {
clearTimeout(this.tickTimer)
this.tickTimer = setTimeout(() => {
if (this.firstTime && !this.firstTrigger) { // 初始不触发
this.domWh = this.getDomInfo(this.$refs['resizeDivRefDom']) // 初始存储宽高信息
} else {
this.emitEvent()
}
this.firstTime = false // 初次渲染成功
}, this.t)
},
addEvents() {
this.removeEvents()
let resizeBox = this.$refs['resizeDivRefDom']
// 1.指定resize事件
this.resizeObserver = new ResizeObserver(this.event_resize) // 会在绘制前和布局后调用 resize 事件,因此不用提前调用 event_resize 方法
// 2.指定该resize事件的触发dom
this.resizeObserver.observe(resizeBox);
},
removeEvents() {
let resizeBox = this.$refs['resizeDivRefDom']
resizeBox && this.resizeObserver?.unobserve(resizeBox)
// 清除定时器
clearTimeout(this.tickTimer)
},
init() {
this.addEvents()
},
},
mounted() {
this.init()
},
beforeDestroy() {
this.removeEvents()
}
}
</script>
<style scoped>
.resize-div {
width: 100%;
height: 100%;
}
</style>
使用
<template>
<div class="mybox" style="height: 20vh;width:100%;">
<rDiv :firstTrigger="false" @resize="divResizeFn">
<div>盒子 resize</div>
</rDiv>
</div>
</template>
...
import resizeDiv from '@/components/resizeDiv/index.vue'
export default {
components: {
rDiv: resizeDiv,
},
...
这里使用vue封装了个 resizeDiv 组件,当外层div盒子宽高发生变化将触发resize事件。
扩展 - 实现 echarts 的 resize
vue项目中可以封装为指令,结合 echarts 实现 echarts resize,这样比监听 window 的 resize 精确得多,这里就不贴代码了,代码很简单,参考上面分分钟写出来,大家自己写吧。
组件使用
使用 v-resize 监听 echart 容器是否宽高发生变化,发生变化后执行该 chart 的resize 事件。【注意:v-resize 是自己写的全局指令,很简单,参考上面代码自行实现。】
image.png
若对你有帮助,请点个赞吧,若能打赏不胜感激,谢谢支持!
本文地址:https://www.jianshu.com/p/53e0fd3bf961,转载请注明出处,谢谢。
网友评论