让前端飞WEB前端程序开发web前端技术分享

web api ResizeObserver 的使用

2024-03-11  本文已影响0人  阿巳交不起水电费

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 精确得多,这里就不贴代码了,代码很简单,参考上面分分钟写出来,大家自己写吧。
组件使用

image.png
使用 v-resize 监听 echart 容器是否宽高发生变化,发生变化后执行该 chart 的resize 事件。【注意:v-resize 是自己写的全局指令,很简单,参考上面代码自行实现。】
image.png

若对你有帮助,请点个赞吧,若能打赏不胜感激,谢谢支持!
本文地址:https://www.jianshu.com/p/53e0fd3bf961,转载请注明出处,谢谢。

上一篇下一篇

猜你喜欢

热点阅读