如何获取BootstrapDialog弹窗内div的实际宽高
问题根因
获取到undefined是两个问题叠加导致的:
- 空依赖数组的
useEffect执行时机过早:BootstrapDialog组件默认带开启动画,组件首次挂载时弹窗还处于入场动画阶段,内部DOM没有完成最终布局,部分实现甚至会在动画结束后才渲染内容区,此时要么ref还没绑定到真实DOM,要么元素宽高还没计算完成。 - 兜底值逻辑错误:
wrapperRefPopup.current?.getBoundingClientRect?.()||0这行代码,当可选链返回空值时,兜底的是数字类型的0,从数字上解构width、height属性,得到的结果必然是undefined。
可行解决方案
方案1:对齐弹窗渲染时机,延迟获取尺寸
将弹窗的显隐状态加入useEffect依赖,等弹窗完全打开、动画结束后再读取尺寸:
// 你控制弹窗开关的state,变量名和代码里的open属性对应 const [open, setOpen] = useState(false); useEffect(() => { // 弹窗没打开、ref还没绑定DOM时直接返回 if (!open || !wrapperRefPopup.current) return; // 延迟时间和BootstrapDialog默认入场动画时长对齐,一般为300ms const calcTimer = setTimeout(() => { const { width, height } = wrapperRefPopup.current.getBoundingClientRect(); // 把d3绘图逻辑移到这里执行 const svg = select(svgRefPopup.current); const svgColorCode = select(svgColorCodeRefPopup.current); // 后续绘图逻辑... }, 300); return () => clearTimeout(calcTimer); }, [open]);
方案2:使用ResizeObserver监听容器尺寸,稳定性更高
这种方式不需要猜测动画时长,不管弹窗何时完成渲染、后续窗口/容器尺寸是否变化,都能拿到准确值:
useEffect(() => { if (!open || !wrapperRefPopup.current) return; const resizeObserver = new ResizeObserver((entries) => { for (const entry of entries) { const { width, height } = entry.contentRect; // 拿到准确宽高后执行绘图,可加标记位避免重复绘制 const svg = select(svgRefPopup.current); const svgColorCode = select(svgColorCodeRefPopup.current); // 后续绘图逻辑... } }); resizeObserver.observe(wrapperRefPopup.current); // 组件卸载时取消监听 return () => resizeObserver.disconnect(); }, [open]);
额外注意事项
- 修正兜底值写法:如果要加可选链兜底,不要兜底数字0,应该兜底带宽高属性的对象,比如
const { width, height } = wrapperRefPopup.current?.getBoundingClientRect?.() || { width: 0, height: 0 };,避免解构报错。 - 如果用的BootstrapDialog默认开启了
keepMounted={false}配置,弹窗关闭时内部DOM会被卸载,必须在open为true时再访问ref,否则会拿到null。 - 绘图前不要给内部svg写死固定宽度,等拿到容器实际宽度后再设置svg的width和viewBox,避免图表拉伸变形。
内容的提问来源于stack exchange,提问作者C Sharper
相关产品推荐
相关产品推荐

