简体   繁体   English

Material-UI:类不适用于外部 SVG 图标?

[英]Material-UI: classes isn't working with external SVG icons?

I have created a Material-UI persistent drawer in which there is a list item component that aims to change the icon color whenever a user clicks on the list item.我创建了一个 Material-UI 持久抽屉,其中有一个列表项组件,旨在在用户单击列表项时更改图标颜色。 But my styling is only working with Material-UI icon, not with external SVG.但我的样式仅适用于 Material-UI 图标,不适用于外部 SVG。

Here is codesandbox link for the same project to understand it better.这是同一项目的代码框链接,可以更好地理解它。

Here is my AppBarDrawer.js parent component that renders my listItem component.这是呈现我的 listItem 组件的AppBarDrawer.js父组件。 Working fine and can be ignored工作正常,可以忽略

import React from "react";
import clsx from "clsx";
import { makeStyles, useTheme } from "@material-ui/core/styles";
import Drawer from "@material-ui/core/Drawer";
import CssBaseline from "@material-ui/core/CssBaseline";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import List from "@material-ui/core/List";
import Typography from "@material-ui/core/Typography";
import Divider from "@material-ui/core/Divider";
import IconButton from "@material-ui/core/IconButton";
import MenuIcon from "@material-ui/icons/Menu";
import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
import ChevronRightIcon from "@material-ui/icons/ChevronRight";
import ListItem from "@material-ui/core/ListItem";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";
import InboxIcon from "@material-ui/icons/MoveToInbox";
import MailIcon from "@material-ui/icons/Mail";
import DrawerList from "./components/DrawerList";

const drawerWidth = 240;

const useStyles = makeStyles((theme) => ({
  root: {
    display: "flex"
  },
  appBar: {
    transition: theme.transitions.create(["margin", "width"], {
      easing: theme.transitions.easing.sharp,
      duration: theme.transitions.duration.leavingScreen
    })
  },
  appBarShift: {
    width: `calc(100% - ${drawerWidth}px)`,
    marginLeft: drawerWidth,
    transition: theme.transitions.create(["margin", "width"], {
      easing: theme.transitions.easing.easeOut,
      duration: theme.transitions.duration.enteringScreen
    })
  },
  menuButton: {
    marginRight: theme.spacing(2)
  },
  hide: {
    display: "none"
  },
  drawer: {
    width: drawerWidth,
    flexShrink: 0
  },
  drawerPaper: {
    width: drawerWidth
  },
  drawerHeader: {
    display: "flex",
    alignItems: "center",
    padding: theme.spacing(0, 1),
    // necessary for content to be below app bar
    ...theme.mixins.toolbar,
    justifyContent: "flex-end"
  },
  content: {
    flexGrow: 1,
    padding: theme.spacing(3),
    transition: theme.transitions.create("margin", {
      easing: theme.transitions.easing.sharp,
      duration: theme.transitions.duration.leavingScreen
    }),
    marginLeft: -drawerWidth
  },
  contentShift: {
    transition: theme.transitions.create("margin", {
      easing: theme.transitions.easing.easeOut,
      duration: theme.transitions.duration.enteringScreen
    }),
    marginLeft: 0
  }
}));

export default function PersistentDrawerLeft() {
  const classes = useStyles();
  const theme = useTheme();
  const [open, setOpen] = React.useState(true);

  const handleDrawerOpen = () => {
    setOpen(true);
  };

  const handleDrawerClose = () => {
    setOpen(false);
  };

  return (
    <div className={classes.root}>
      <CssBaseline />
      <AppBar
        position="fixed"
        className={clsx(classes.appBar, {
          [classes.appBarShift]: open
        })}
      >
        <Toolbar>
          <IconButton
            color="inherit"
            aria-label="open drawer"
            onClick={handleDrawerOpen}
            edge="start"
            className={clsx(classes.menuButton, open && classes.hide)}
          >
            <MenuIcon />
          </IconButton>
          <Typography variant="h6" noWrap>
            Persistent drawer
          </Typography>
        </Toolbar>
      </AppBar>
      <Drawer
        className={classes.drawer}
        variant="persistent"
        anchor="left"
        open={open}
        classes={{
          paper: classes.drawerPaper
        }}
      >
        <div className={classes.drawerHeader}>
          <IconButton onClick={handleDrawerClose}>
            {theme.direction === "ltr" ? (
              <ChevronLeftIcon />
            ) : (
              <ChevronRightIcon />
            )}
          </IconButton>
        </div>
        <Divider />
        <List>
          <DrawerList />
        </List>
      </Drawer>
      <main
        className={clsx(classes.content, {
          [classes.contentShift]: open
        })}
      >
        <div className={classes.drawerHeader} />

        <Typography paragraph>
          Lorem Nulla posuere sollicitudin aliquam ultrices sagittis orci a
        </Typography>
      </main>
    </div>
  );
}

The Main file DrawerList.js which is not giving desired out没有给出期望的主文件DrawerList.js

Here the real issue is my external icons color is not changing to white whenever I click on it however the last icon named ExitToAppOutlined is a Material-UI icon and is working fine on click.这里真正的问题是,每当我点击它时,我的外部图标颜色都不会变为白色,但是最后一个名为ExitToAppOutlined的图标是 Material-UI 图标,点击时效果很好。

import React, { useState } from "react";
import ListItem from "@material-ui/core/ListItem";
import Link from "@material-ui/core/Link";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import { ExitToAppOutlined } from "@material-ui/icons";
import ListItemText from "@material-ui/core/ListItemText";
import { useStyles } from "./DrawerListStyle";
import Typography from "@material-ui/core/Typography";
import Box from "@material-ui/core/Box";
import { SvgIcon } from "@material-ui/core";

import { ReactComponent as Appointment } from "../../assets/Appointment.svg";
import { ReactComponent as Customers } from "../../assets/manage customers 2.svg";

const itemList = [
  {
    text: "Book Appointment",
    icon: (
      <SvgIcon>
        {/* external icons as svg */}
        <Appointment />
      </SvgIcon>
    )
  },
  {
    text: "Manage",
    icon: (
      <SvgIcon>
        {/* external icons as svg */}
        <Customers />
      </SvgIcon>
    )
  },
  {
    text: "Logout",
    // Material Icons
    icon: <ExitToAppOutlined />
  }
];

const DrawerList = () => {
  const [selectedIndex, setSelectedIndex] = useState(0);
  const classes = useStyles();

  const ListData = () =>
    itemList.map((item, index) => {
      const { text, icon } = item;

      return (
        <ListItem
          button
          key={text}
          component={Link}
          selected={index === selectedIndex}
          onClick={(e) => handleListItemClick(e, index)}
          style={selectedIndex === index ? { backgroundColor: "#6A2CD8" } : {}}
        >
          <ListItemIcon
            className={classes.iconStyle}
            style={selectedIndex === index ? { color: "#fff" } : {}}
          >
            {icon}
            <ListItemText>
              <Typography
                component="div"
                className={classes.iconTitle}
                style={selectedIndex === index ? { color: "#fff" } : {}}
              >
                <Box fontWeight={500} fontSize={13.5}>
                  {text}
                </Box>
              </Typography>
            </ListItemText>
          </ListItemIcon>
        </ListItem>
      );
    });
  const handleListItemClick = (e, index) => {
    setSelectedIndex(index);
  };

  return (
    <div className={classes.root}>
      <ListData />
    </div>
  );
};

export default DrawerList;

DrawerListStyle.js just an stylejs file and can be ignored DrawerListStyle.js只是一个 stylejs 文件,可以忽略

import { makeStyles } from "@material-ui/core";

const useStyles = makeStyles((theme) => ({
  root: {
    marginTop: theme.spacing(2)
  },
  iconStyle: {
    margin: theme.spacing(0, 0, 1, 0),
    color: "#6A2CD8"
  },
  iconTitle: {
    margin: theme.spacing(0, 0, 0, 1),
    color: "#555458"
  }
}));

export { useStyles };

Material-UI sets the color of your ListItemIcon when the ListItem is selected, but because your custom svg icons already have the fill attribute set to another color, it overrides the color from MUI. Material-UI 在选择ListItemIcon时设置ListItemcolor ,但是因为您的自定义svg图标已经将fill属性设置为另一种颜色,它会覆盖 MUI 中的color The fix is simple, override the fill attribute again in your custom svg using makeStyles :修复很简单,使用makeStyles在您的自定义 svg 中再次覆盖fill属性:

const useStyles = makeStyles((theme) => ({
  {...}
  listItem: {
    "&.Mui-selected": {
      "& path": {
        fill: "white"
      }
    }
  }
}));
<ListItem className={classes.listItem}

Live Demo现场演示

编辑 67092230/why-material-ui-classes-isnt-working-with-external-svg-icon

you can also use SVGR to build your own icons.您还可以使用SVGR构建自己的图标。

you can follow these steps:您可以按照以下步骤操作:

1- install svgr using 1-使用安装 svgr

npm install --save-dev @svgr/cli
# or use yarn
yarn add --dev @svgr/cli

2- add your icons in public/icons 2-在public/icons

3- create a file named svgr.config.js and place it in the root of project 3-创建一个名为svgr.config.js的文件并将其放在项目的根目录中

module.exports = {
    icon: true,
    dimensions: false,
    expandProps: false,
    replaceAttrValues: {
        '#000': 'currentColor',
        '#292D32': 'currentColor',
        '#292d32': 'currentColor',
        '#55BB9D': 'currentColor',
        '#FFBC50': 'currentColor',
        '#A7A7A7': 'currentColor'
    }
};

4- add script in package.json "svg": "svgr --ext=jsx -d src/@share/icons public/icons" 4- 在 package.json "svg": "svgr --ext=jsx -d src/@share/icons public/icons"中添加脚本

5 - run yarn svg . 5 运行yarn svg

once you run above command svgr grab all icons in the public folder and gerenate React component inside src/@share/icons folder based on the config you provided.一旦你运行上面的命令 svgr 抓取公共文件夹中的所有图标,并根据你提供的配置在src/@share/icons文件夹中生成 React 组件。 and replace every color text of svg into current color.并将 svg 的每个颜色文本替换为当前颜色。 in this case replace every key in replaceAttrValues to the currentColor .在这种情况下,将replaceAttrValues中的每个键替换为currentColor

then in your react component you can simply do this:然后在您的反应组件中,您可以简单地执行以下操作:

import { MyIcon } from '@share/icons';
import { SvgIcon } from '@mui/material';

function MyComponent() {
    return <p><SvgIcon component={MyIcon} /> check this icon </p>
};

export default MyComponent;

in this way you can change the color the way you change the text color of p element.这样,您可以像更改p元素的文本颜色一样更改颜色。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM