You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

微前端下无法访问sidebar,如何监听其clientWidth变化并获取?

解决微前端下捕获sidebar宽度变化的问题

你的代码里有两个核心问题导致拿不到sidebar宽度:

  1. document是全局对象,永远不会变化,所以useEffect只会执行一次,要是执行时sidebar还没渲染(微前端异步加载的特性),自然拿不到值
  2. 没有监听sidebar宽度的动态变化,就算第一次拿到值,后续sidebar宽度改变也无法捕获

下面给几个实用的解决办法:

方案一:用ResizeObserver+MutationObserver组合监听

先通过MutationObserver等待sidebar元素出现,再用ResizeObserver监听它的宽度变化,完美适配微前端异步加载的场景:

import { Box, BoxProps, HStack } from '@chakra-ui/react';
import React, { useEffect, useState } from 'react';

interface Props extends BoxProps {
    leftActions?: React.ReactNode[];
    rightActions?: React.ReactNode[];
}

export const FormFooter = ({ leftActions, rightActions, ...props }: Props) => {
    const [sidebarWidth, setSidebarWidth] = useState(0);

    useEffect(() => {
        let resizeObserver: ResizeObserver | null = null;
        const sidebarSelector = '.css-ygpt8u';

        // 监听元素是否出现
        const mutationObserver = new MutationObserver(() => {
            const sidebarEl = document.querySelector(sidebarSelector);
            if (sidebarEl && !resizeObserver) {
                // 元素出现后,监听宽度变化
                resizeObserver = new ResizeObserver(entries => {
                    const width = entries[0].contentRect.width;
                    setSidebarWidth(width);
                    console.log('sidebarWidth updated:', width);
                });
                resizeObserver.observe(sidebarEl);
                // 先获取一次初始宽度
                setSidebarWidth((sidebarEl as HTMLElement).clientWidth);
            }
        });

        // 监听整个文档的DOM变化
        mutationObserver.observe(document.body, {
            childList: true,
            subtree: true,
        });

        return () => {
            mutationObserver.disconnect();
            resizeObserver?.disconnect();
        };
    }, []);

    return (
        <Box
            display={'flex'}
            justifyContent={'space-between'}
            {...props}
            width={`calc(100vw - ${sidebarWidth + 84}px)`} // 用动态宽度替换固定值
            backgroundColor="white"
        >
            <HStack key="form-left">{leftActions?.map((element) => element)}</HStack>
            <HStack key="form-right">{rightActions?.map((element) => element)}</HStack>
        </Box>
    );
};

方案二:利用微前端通信传递宽度(最优解)

既然是微前端架构,sidebar所在的子应用可以主动把宽度变化通知给当前应用,避免DOM查询的耦合:

  1. 在sidebar所在的子应用中,监听自身宽度变化并发送自定义事件:
// sidebar子应用代码
const sidebarEl = document.querySelector('.css-ygpt8u');
if (sidebarEl) {
    const resizeObserver = new ResizeObserver(entries => {
        const width = entries[0].contentRect.width;
        // 发送自定义事件传递宽度
        window.dispatchEvent(new CustomEvent('sidebar-width-change', {
            detail: { width }
        }));
    });
    resizeObserver.observe(sidebarEl);
    // 初始发送一次宽度值
    window.dispatchEvent(new CustomEvent('sidebar-width-change', {
        detail: { width: sidebarEl.clientWidth }
    }));
}
  1. 在当前应用的FormFooter组件中监听这个事件:
import { Box, BoxProps, HStack } from '@chakra-ui/react';
import React, { useEffect, useState } from 'react';

interface Props extends BoxProps {
    leftActions?: React.ReactNode[];
    rightActions?: React.ReactNode[];
}

export const FormFooter = ({ leftActions, rightActions, ...props }: Props) => {
    const [sidebarWidth, setSidebarWidth] = useState(0);

    useEffect(() => {
        const handleSidebarWidthChange = (e: CustomEvent) => {
            const newWidth = e.detail.width;
            setSidebarWidth(newWidth);
            console.log('sidebarWidth updated:', newWidth);
        };

        window.addEventListener('sidebar-width-change', handleSidebarWidthChange as EventListener);

        // 组件卸载时移除监听
        return () => {
            window.removeEventListener('sidebar-width-change', handleSidebarWidthChange as EventListener);
        };
    }, []);

    return (
        <Box
            display={'flex'}
            justifyContent={'space-between'}
            {...props}
            width={`calc(100vw - ${sidebarWidth + 84}px)`}
            backgroundColor="white"
        >
            <HStack key="form-left">{leftActions?.map((element) => element)}</HStack>
            <HStack key="form-right">{rightActions?.map((element) => element)}</HStack>
        </Box>
    );
};

方案三:定时轮询(兜底方案)

如果上面两种方案都没法实现,可以用定时轮询兜底,虽然不够优雅但简单有效:

import { Box, BoxProps, HStack } from '@chakra-ui/react';
import React, { useEffect, useState } from 'react';

interface Props extends BoxProps {
    leftActions?: React.ReactNode[];
    rightActions?: React.ReactNode[];
}

export const FormFooter = ({ leftActions, rightActions, ...props }: Props) => {
    const [sidebarWidth, setSidebarWidth] = useState(0);

    useEffect(() => {
        const intervalId = setInterval(() => {
            const sidebarEl = document.querySelector<HTMLElement>('.css-ygpt8u');
            if (sidebarEl) {
                const newWidth = sidebarEl.clientWidth;
                if (newWidth !== sidebarWidth) {
                    setSidebarWidth(newWidth);
                    console.log('sidebarWidth updated:', newWidth);
                }
            }
        }, 300); // 每隔300ms查询一次,可按需调整

        return () => clearInterval(intervalId);
    }, [sidebarWidth]);

    return (
        <Box
            display={'flex'}
            justifyContent={'space-between'}
            {...props}
            width={`calc(100vw - ${sidebarWidth + 84}px)`}
            backgroundColor="white"
        >
            <HStack key="form-left">{leftActions?.map((element) => element)}</HStack>
            <HStack key="form-right">{rightActions?.map((element) => element)}</HStack>
        </Box>
    );
};

注意事项

  • 尽量避免用css-ygpt8u这种动态生成的样式类,微前端不同环境下可能会变化,最好让sidebar暴露固定自定义属性(比如data-sidebar),用[data-sidebar]查询更可靠
  • 方案二是最优解,完全解耦了两个微应用,符合微前端架构设计原则

内容的提问来源于stack exchange,提问作者Nasir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 09:05:39