vue3 封装自定义指令,监听元素宽高的变化

本文介绍了如何在Vue项目中利用ResizeObserver监听DOM元素的宽高变化,以实现Echarts图表根据父元素动态调整大小。作者提供了步骤包括创建自定义指令、全局注册以及在模板中使用该指令的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近做一个项目,涉及到echart图,要去根据父元素去自适应宽高,所以需要监听到元素的宽高变化、

因为是监听某一元素的宽高变化,所以这里用的是ResizeObserver.

ResizeObserver是可以监听到DOM元素,宽高的变化,需要注意的一点就是监听出变化结果是contentBox的宽度和高度。

以下为浏览器兼容性

在这里插入图片描述

第一步:封装自定义指令

在directive文件夹下创建一个resizeObserver.js文件
内容如下

// 监听元素大小变化的指令
const map = new WeakMap()
const ob = new ResizeObserver((entries) => {
    for (const entry of entries) {
        // 获取dom元素的回调
        const handler = map.get(entry.target)
        //存在回调函数
        if (handler) {
            // 将监听的值给回调函数
            handler({
                width: entry.borderBoxSize[0].inlineSize,
                height: entry.borderBoxSize[0].blockSize
            })
        }
    }
})


export const Resize = {

    mounted(el, binding) {
        //将dom与回调的关系塞入map
        map.set(el, binding.value)
        //监听el元素的变化
        ob.observe(el)
    },
    unmounted(el) {
        //取消监听
        ob.unobserve(el)
    }
}

export default Resize


第二步:在directive文件夹再创建一个index.js文件,目的是为了集中注册自定义指令

import { Resize } from "./resizeObserver"


// 自定义指令集合
const directives = {
    Resize,
}

export default {
    install(app) {
        Object.keys(directives).forEach((key) => {
            app.directive(key, directives[key])
        })
    }
}


第三步:在main.js文件进行全局注册

import directives from "@/util/directive/index"
app.use(directives)

第四步:使用方法

<template>
<div style="height: 100%; width: 100%" v-resize="onResize"></div>
</template>
<script setup>
// 当元素宽高发生变化时,触发下面的方法
const onResize = (dom) => {
    console.log(dom) // dom为元素变化后的宽高
}
</script>



以上,希望大家一键三连哇~~ 感谢

<think>好的,我现在要帮助用户解决在Vue3中如何监听DOM元素变化的问题。首先,我需要回顾用户提供的历史对话和现有的引用资料,确保理解他们的需求和之前的讨论。 用户之前的问题是关于如何获取元素,现在他们想在Vue3监听这些尺寸的变化。根据提供的引用内容,有几个方法被提到,比如使用ResizeObserver,elementResizeDetectorMaker,以及可能遇到的问题,比如watch无法监听offsetWidth的变化。 首先,我需要确认Vue3中的推荐做法。根据现代浏览器的支持情况,ResizeObserver是一个强大的API,可以有效地监听元素尺寸变化。引用2、3、4都提到了使用ResizeObserver的方法,特别是在Vue3的setup语法中使用。因此,这应该是主要的解决方案。 接下来,用户可能在Vue2中使用过element-resize-detector库(引用1),但在Vue3中是否同样适用?需要确认该库是否兼容Vue3,但考虑到Vue3的组合式API和响应式系统的变化,可能更推荐使用原生的ResizeObserver,因为它在现代浏览器中得到广泛支持,并且不需要额外的依赖。 然后,用户提到的watch监听$refs.swiper.offsetWidth失败的问题(引用5)。这可能是因为offsetWidth不是响应式属性,直接watch无法捕获其变化。这时候需要解释为什么watch不工作,并强调使用ResizeObserver的必要性。 接下来需要组织步骤,确保回答结构清晰。可能的结构包括:使用ResizeObserver的基本方法、在组件生命周期中管理观察者、封装自定义指令、处理SSR兼容性等。同时,要提到注意事项,比如组件卸载时取消观察,避免内存泄漏。 需要检查引用中的代码示例,特别是引用3和4中的Vue3示例,确保语法正确,比如使用ref、onMounted、onUnmounted等组合式API。同时,可能提到将逻辑封装自定义hook或工具函数中,提代码复用性,如引用4中的getWidth函数。 另外,用户可能关心性能问题,比如频繁的回调是否会影响性能,是否需要防抖处理。因此,在回答中可以建议使用防抖技术优化变化的处理。 最后,需要确保回答符合用户的要求,使用中文,结构清晰,并引用相关的引用资料。同时,生成相关问题,帮助用户进一步学习。</think>在Vue3监听DOM元素变化,推荐使用现代浏览器原生支持的$ResizeObserver$ API,以下是三种实现方案及注意事项: --- ### 一、基础实现方案(推荐) #### 1. 组合式API实现 ```vue <template> <div ref="targetElement" class="resizable-box"></div> </template> <script setup> import { ref, onMounted, onUnmounted } from &#39;vue&#39; const targetElement = ref(null) let observer = null // 尺寸变化回调 const handleResize = (entries) => { const { width, height } = entries[0].contentRect console.log(`新宽度:${width}px,新度:${height}px`) // 这里触发业务逻辑,如更新图表、调整布局等 } // 生命周期管理 onMounted(() => { observer = new ResizeObserver(handleResize) observer.observe(targetElement.value) }) onUnmounted(() => { if (observer) observer.disconnect() }) </script> ``` - 通过$ref$绑定目标元素[^3] - 使用$onMounted$确保DOM已渲染[^3] - 组件卸载时自动断开监听[^4] --- ### 二、进阶封装方案 #### 1. 自定义Hook复用逻辑 ```javascript // useResizeObserver.js import { onUnmounted } from &#39;vue&#39; export function useResizeObserver(elementRef, callback) { const observer = new ResizeObserver(entries => { callback(entries[0].contentRect) }) observer.observe(elementRef.value) onUnmounted(() => { observer.disconnect() }) } ``` 组件内调用: ```vue <script setup> import { ref } from &#39;vue&#39; import { useResizeObserver } from &#39;./useResizeObserver&#39; const boxRef = ref(null) useResizeObserver(boxRef, (rect) => { console.log(&#39;尺寸变化:&#39;, rect) }) </script> ``` #### 2. 自定义指令封装 ```javascript // resizeObserverDirective.js export const vResize = { mounted(el, binding) { const observer = new ResizeObserver(entries => { binding.value(entries[0].contentRect) }) observer.observe(el) el._resizeObserver = observer }, unmounted(el) { el._resizeObserver?.disconnect() } } ``` 注册指令后使用: ```vue <div v-resize="handleResize"></div> ``` --- ### 三、特殊场景处理 #### 1. 响应式组件容器 当元素尺寸依赖父容器时,需监听元素: ```javascript // 在onMounted中 const parentElement = targetElement.value.parentElement observer.observe(parentElement) ``` #### 2. 性能优化 变化时添加防抖: ```javascript import { debounce } from &#39;lodash-es&#39; const handleResize = debounce((entries) => { // 业务逻辑 }, 200) ``` #### 3. SSR兼容方案 ```javascript import { isClient } from &#39;vue-demi&#39; if (isClient) { // 浏览器环境才执行监听 } ``` --- ### 关键问题解析 1. **为什么watch监听$refs.xxx.offsetWidth会失败?** DOM属性变更不属于Vue响应式系统追踪范围,必须通过事件监听实现[^5] 2. **与Vue2方案的差异** Vue3推荐使用组合式API替代mixins,且$elementResizeDetector$库需验证Vue3兼容性[^1] 3. **观测精度控制** ResizeObserver默认监测布局尺寸变化,可通过`box`选项指定观测模式: ```javascript observer.observe(element, { box: &#39;content-box&#39; }) // 仅内容区域 ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值