如何获取位于其他组件内部、已渲染完成的元素的实际高度?
跨组件获取已渲染元素高度的解决方法
问题根因
你当前的实现直接在组件顶层查询DOM,此时目标元素所在的组件还未完成挂载、浏览器也没有完成布局计算,所以首次读取到的offsetHeight为0。热重载时应用全局DOM已经完成渲染,所以可以拿到正确值。
方案1:无需修改目标组件(推荐适配现有代码)
使用ResizeObserver配合MutationObserver监听DOM变化,无论目标元素何时挂载都能拿到正确高度:
import { useState, useEffect, useMemo } from 'react'; // 你的组件内部 const [stepperHeight, setStepperHeight] = useState(0); useEffect(() => { // 非浏览器环境直接跳过,适配SSR场景 if (typeof window === 'undefined') return; const updateHeight = () => { const el = document.querySelector('.step-indicator'); if (el) { setStepperHeight(el.offsetHeight); return true; } return false; }; // 首次尝试获取高度 if (updateHeight()) return; // 监听高度变化 const resizeObserver = new ResizeObserver(entries => { for (const entry of entries) { setStepperHeight(entry.target.offsetHeight); } }); // 监听DOM树变化,等待目标元素挂载 const mutationObserver = new MutationObserver(() => { if (updateHeight()) { const el = document.querySelector('.step-indicator'); resizeObserver.observe(el); mutationObserver.disconnect(); } }); mutationObserver.observe(document.body, { childList: true, subtree: true }); // 组件卸载时清理观察者,避免内存泄漏 return () => { resizeObserver.disconnect(); mutationObserver.disconnect(); }; }, []); const minHeight = useMemo(() => { return stepperHeight ? `calc(${stepperHeight}px + var(--small-spacing))` : 'auto'; }, [stepperHeight]);
该方案同时支持元素动态挂载、高度后续动态更新的场景。
方案2:符合React最佳实践(可修改目标组件时使用)
避免直接查询全局DOM,通过forwardRef暴露目标元素引用,配合状态管理同步高度:
// step-indicator 所在组件 import { forwardRef, useLayoutEffect, useRef } from 'react'; // 可替换为你项目在用的状态管理工具(Redux/Context/Zustand等) import { useGlobalStore } from '@/store/global'; const StepIndicator = forwardRef((props, ref) => { const setStepperHeight = useGlobalStore(state => state.setStepperHeight); const innerRef = useRef(null); const targetRef = ref || innerRef; useLayoutEffect(() => { if (targetRef.current) { setStepperHeight(targetRef.current.offsetHeight); } }, []); return <div className="step-indicator" ref={targetRef} {...props} />; }); // 你的组件内部直接读状态即可 const stepperHeight = useGlobalStore(state => state.stepperHeight); const minHeight = useMemo(() => { return stepperHeight ? `calc(${stepperHeight}px + var(--small-spacing))` : 'auto'; }, [stepperHeight]);
该方案性能更稳定,不会出现DOM查询冲突的问题。
内容的提问来源于stack exchange,提问作者RMT
相关产品推荐
相关产品推荐

