当前位置: 首页 > news >正文

【ResizeObserver】【页面布局】监听一个 div 元素的动态高度变化并同步设置另一个元素的高度

在 Vue3 中监听一个 div 元素的动态高度变化并同步设置另一个元素的高度,最佳实践是使用 ResizeObserver API。

在开发中,常有上中下分布列表页,如下:
需求现象 :列表滚动区域需要具体高度来滚动,但是搜索区域会随页面拉伸等变化高度。
在这里插入图片描述

处理方法一:最佳方案:使用 ResizeObserver

  • ResizeObserver API​​:
    现代浏览器原生支持,高效监听元素尺寸变化
    比轮询或MutationObserver性能更好
  • ​​生命周期管理​​:
    onMounted中初始化观察器
    onBeforeUnmount中清理观察器,避免内存泄漏
  • ​​初始高度设置​​:
    在开始观察前先同步一次初始高度
  • ​​平滑过渡​​:
    通过CSS transition实现高度变化的动画效果
	<template><div class="container"><!-- 高度会动态变化的源元素 --><div ref="sourceRef" class="source-element">内容可能动态变化导致高度改变...</div><!-- 需要同步高度的目标元素 --><div ref="targetRef" class="target-element">我的高度会跟随上方元素</div></div></template><script setup>import { ref, onMounted, onBeforeUnmount } from 'vue'const sourceRef = ref(null)const targetRef = ref(null)let resizeObserver = null// 处理高度变化的回调函数const handleResize = (entries) => {if (!targetRef.value) returnfor (let entry of entries) {const { height } = entry.contentRecttargetRef.value.style.height = `${height}px`// 也可以使用CSS变量:// targetRef.value.style.setProperty('--dynamic-height', `${height}px`)}}onMounted(() => {// 初始化观察器resizeObserver = new ResizeObserver(handleResize)if (sourceRef.value) {// 开始观察源元素resizeObserver.observe(sourceRef.value)// 初始设置一次高度const initHeight = sourceRef.value.getBoundingClientRect().heighttargetRef.value.style.height = `${initHeight}px`}})onBeforeUnmount(() => {// 组件卸载时停止观察if (resizeObserver) {resizeObserver.disconnect()}// 或// resizeObserver?.disconnect()})</script><style>.source-element {border: 1px solid #ccc;padding: 20px;/* 高度由内容决定 */}.target-element {border: 1px solid #f0f;margin-top: 10px;overflow: hidden;transition: height 0.3s ease; /* 添加平滑过渡效果 */}</style>

优化—响应式地存储高度值

这种方法将高度值存储在响应式变量中,便于在其他地方使用。

	<script setup>import { ref, onMounted, onBeforeUnmount } from 'vue'const sourceRef = ref(null)const targetRef = ref(null)const dynamicHeight = ref(0)let resizeObserver = nullonMounted(() => {resizeObserver = new ResizeObserver((entries) => {entries.forEach(entry => {dynamicHeight.value = entry.contentRect.height})})if (sourceRef.value) {resizeObserver.observe(sourceRef.value)}})// 使用watch监听高度变化watch(dynamicHeight, (newHeight) => {if (targetRef.value) {targetRef.value.style.height = `${newHeight}px`}})onBeforeUnmount(() => {resizeObserver?.disconnect()})</script>

使用 @resize 事件(需配合自定义指令)

如果项目中频繁需要监听尺寸变化,可以封装一个自定义指令:

// directives/resize.js
export default {mounted(el, binding) {const callback = binding.value;const observer = new ResizeObserver((entries) => {callback(entries[0].contentRect);});observer.observe(el);el._resizeObserver = observer;},unmounted(el) {if (el._resizeObserver) {el._resizeObserver.disconnect();}},
};
<template><div v-resize="onSourceResize">源元素</div><div :style="{ height: targetHeight + 'px' }">目标元素</div>
</template><script setup>
import { ref } from 'vue';
import resizeDirective from './directives/resize';const targetHeight = ref(0);const onSourceResize = (rect) => {targetHeight.value = rect.height;
};
</script>

注意事项
性能:ResizeObserver 是异步触发的,避免在回调中执行高耗能操作。
兼容性:如果需要支持旧浏览器,需引入 resize-observer-polyfill。
初始高度:在 onMounted 中可能需要手动设置一次初始高度。

完整示例(基于 ResizeObserver)

<template><div ref="source" class="source"><p>源元素内容(高度可能变化)</p><button @click="addContent">增加内容</button></div><div ref="target" class="target" :style="{ height: targetHeight + 'px' }">目标元素(高度同步源元素)</div>
</template><script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';const source = ref(null);
const target = ref(null);
const targetHeight = ref(0);
let observer = null;const updateHeight = () => {if (source.value) {targetHeight.value = source.value.offsetHeight;}
};onMounted(() => {observer = new ResizeObserver(updateHeight);if (source.value) {observer.observe(source.value);updateHeight(); // 初始化高度}
});onBeforeUnmount(() => {if (observer) observer.disconnect();
});const addContent = () => {const p = document.createElement('p');p.textContent = '新增内容 ' + Math.random();source.value.appendChild(p);
};
</script><style>
.source {border: 1px solid blue;padding: 10px;margin-bottom: 10px;
}
.target {border: 1px solid red;padding: 10px;background: #eee;
}
</style>

代替方案比较:

在这里插入图片描述

http://www.dtcms.com/a/296992.html

相关文章:

  • Windows环境下 Go项目迁移至Ubuntu(WSL) 以部署filebeat为例
  • 【数组的定义与使用】
  • 保障工业核心命脉:深度解读工业交换机QoS的“智能流量治理”之道
  • CMake ARGV变量使用指南
  • Python桌面版数独(五版)-优化选择模式触发新棋盘生成
  • OSPF 实验
  • RuoYi-Vue 项目 Docker 全流程部署实战教程
  • 中国、美国、欧盟、日本、英国临床试验API数据接口
  • Ⅹ—6.计算机二级综合题7---10套
  • Mac系统机能连接操控别的平台设备吗?能被远程操作吗?
  • Nginx快速入门及案例
  • 【安卓笔记】解决livedata粘性事件
  • 《Java语言程序设计》第2章复习题(2)
  • RePlugin 坑位使用原理与指南
  • 多源信息融合智能投资【“图神经网络+强化学习“的融合架构】【低配显卡正常运行】
  • 模拟退火算法 (Simulated Annealing, SA)简介
  • JavaWeb学习打卡14(JSP内置对象及作用域)
  • ARM汇编常见伪指令及其用法示例
  • IntelliJ IDEA中管理多版本Git子模块的完整指南
  • 智慧工厂网络升级:新型 SD-WAN 技术架构与应用解析
  • 商场导航软件:3D+AI 基于Deepseek 模型的意图识别技术解析
  • BacNet 是什么?跟 LoRaWAN 的关系是什么?
  • 将JS字节流转化为对象
  • 西安交通大学XJTU 通信/信息工程大三和部分大四 实验和课程答案
  • C++哪些运算符不能被重载?
  • kubernetes集群中部署CoreDNS服务
  • day46day47 通道注意力
  • 一种基于单片机控制的太阳能电池板系统设计
  • 集训Demo6
  • 挖掘录屏宝藏:Screenity 深度解析与使用指南