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

如何从不同DOM的Button组件为Styled Menu组件添加样式?

问题

在使用Material-UI的Menu组件时,Dashboard按钮和下拉菜单属于同一组件文件但分属不同DOM结构。我尝试通过Button的styled组件(DisplayButton)为Menu的styled组件(DisplayMenu)添加样式,但当前写法无法生效。虽然直接在DisplayMenu中编写样式可以正常工作,但实际场景更复杂,因此想确认这种跨DOM结构的样式写法是否可行?

组件代码(index.jsx)

import * as React from 'react';
import MenuItem from '@mui/material/MenuItem';
import {DisplayMenu, DisplayButton} from './styles'

export default function BasicMenu() {
  const [anchorEl, setAnchorEl] = React.useState(null);
  const open = Boolean(anchorEl);
  const handleClick = (event) => {
    setAnchorEl(event.currentTarget);
  };
  const handleClose = () => {
    setAnchorEl(null);
  };

  return (
    <div>
      <DisplayButton
        id="basic-button"
        aria-controls={open ? 'basic-menu' : undefined}
        aria-haspopup="true"
        aria-expanded={open ? 'true' : undefined}
        onClick={handleClick}
      >
        Dashboard
      </DisplayButton>
      <DisplayMenu
        id="basic-menu"
        anchorEl={anchorEl}
        open={open}
        onClose={handleClose}
        MenuListProps={{
          'aria-labelledby': 'basic-button',
        }}
      >
        <MenuItem onClick={handleClose}>Profile</MenuItem>
        <MenuItem onClick={handleClose}>My account</MenuItem>
        <MenuItem onClick={handleClose}>Logout</MenuItem>
      </DisplayMenu>
    </div>
  );
}

样式代码(styles.js)

import styled from 'styled-components';
import Button from '@mui/material/Button';
import Menu from '@mui/material/Menu';

export const DisplayMenu = styled(Menu)`
  padding: 20px;
`;

DisplayMenu.displayName = 'DisplayMenu';

export const DisplayButton = styled(Button)`
  margin: 10px;

  ${DisplayMenu}{
    & .MuiPaper-root {
      width: 300px;
  }
  }
`;

DisplayButton.displayName = 'DisplayButton';

已知直接在DisplayMenu中添加样式可生效:

export const DisplayMenu = styled(Menu)`
  padding: 20px;
  & .MuiPaper-root {
      width: 300px;
  }
`;

解决方案

为什么当前写法不生效?

styled-components的嵌套语法${DisplayMenu}仅用于选中当前组件内部的子元素,但DisplayMenu和DisplayButton是同级DOM元素,并非父子关系,因此无法通过这种方式选中目标组件。

可行替代方案

  1. 通过父容器统一控制样式
    给两个组件的父容器创建styled组件,在其中统一管理子组件的样式:

    import styled from 'styled-components';
    import Button from '@mui/material/Button';
    import Menu from '@mui/material/Menu';
    
    const MenuContainer = styled.div`
      ${DisplayButton} {
        margin: 10px;
      }
    
      ${DisplayMenu} {
        padding: 20px;
        & .MuiPaper-root {
          width: 300px;
        }
      }
    `;
    
    export const DisplayMenu = styled(Menu)``;
    export const DisplayButton = styled(Button)``;
    

    组件中用MenuContainer包裹两个元素:

    return (
      <MenuContainer>
        <DisplayButton ...>Dashboard</DisplayButton>
        <DisplayMenu ...>...</DisplayMenu>
      </MenuContainer>
    );
    
  2. 利用同级选择器配合自定义类名
    给DisplayMenu添加自定义类名,通过CSS同级选择器(~)控制样式:

    export const DisplayMenu = styled(Menu)`
      padding: 20px;
    `;
    
    export const DisplayButton = styled(Button)`
      margin: 10px;
      & ~ .custom-menu .MuiPaper-root {
        width: 300px;
      }
    `;
    

    组件中给DisplayMenu绑定类名:

    <DisplayMenu className="custom-menu" ...>...</DisplayMenu>
    
  3. Material-UI主题定制
    如果是对Material-UI组件的默认样式调整,可通过自定义主题统一配置:

    import { createTheme, ThemeProvider } from '@mui/material/styles';
    
    const theme = createTheme({
      components: {
        MuiMenu: {
          styleOverrides: {
            paper: {
              width: 300,
            },
          },
        },
      },
    });
    

    在应用外层包裹ThemeProvider即可让所有Menu组件生效,也可结合theme.vars实现更灵活的styled-components定制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 11:15:44