如何使用它的snake_case名称动态加载图标(React,material-ui)

问题描述 投票:0回答:8

通常我会通过直接导入来使用material-ui图标按照material-ui说明

但是我有一个文本标签,它是实际的图标名称(如

calendar_view_day
),需要动态地从中获取和渲染图标组件。

我怎样才能像:

render() {
  return (
    <Icon name="calendar_view_day" color="primary" />
  )
}

代替:

render() {
  return (
    <CalendarViewDay color="primary" />  // Imported by name
  )
}
reactjs icons material-design material-ui
8个回答
21
投票

后期编辑

编辑 2:在使用以下内容之前,请先查看 @Roozbeh 在 2023 年中期关于使用字体材质图标的最新答案。


编辑1:这个答案适用于MUI v4,MUI v5答案如下(但未经我测试)

正确答案

原来

material-ui
包含一个图标组件,允许您执行此操作...并且它本身会转换名称,因此接受 Snake、Pascal 和其他变体。 请注意,正如评论中指出的那样,这将大大增加捆绑包的大小。如果您的捆绑包大小受到限制,则必须采取不同的方法从某处提供图标 SVG!

import Icon from '@material-ui/core/Icon'

...

render() {
  return (
    <Icon>{props.iconName}</Icon>
  )
}

之前的答案(有效但过度杀伤力)

创建函数:

...然后使用material-ui Icon组件。

这是代码:

import Icon from '@material-ui/core/Icon'

function upperFirst(string) {
  return string.slice(0, 1).toUpperCase() + string.slice(1, string.length)
}

function fixIconNames(string) {
  const name = string.split('_').map(upperFirst).join('')
  if (name === '3dRotation') {
    return 'ThreeDRotation'
  } else if (name === '4k') {
    return 'FourK'
  } else if (name === '360') {
    return 'ThreeSixty'
  }
  return name
}

...

render() {
  const iconName = fixIconNames(props.iconName)
  return (
    <Icon>{props.iconName}</Icon>
  )
}

5
投票

MUI 5 开发人员在这里。

import * as Muicon from "@mui/icons-material";
const Icon = Muicon['SatelliteAlt']
<Icon fontSize="large" sx={{ px: 1 }}/>

打字稿

import * as MUIcon from "@mui/icons-material";
interface IconProps {
   icon?: keyof typeof MUIcon;
}
const IconComp: React.FC<IconProps> = ({
  icon,
}) => {
    const Icon = icon && MUIcon[icon];
    return ({Icon && <Icon />})
}

2
投票

伙计们,快到 2024 年了,请使用字体材质图标。超轻量:

npm install material-icons@latest

在 JS 中导入(例如:Create React App 中的

src/index.js
、NextJS 中的
src/_app.js
、Vue CLI 中的
src/main.js
):

import 'material-icons/iconfont/material-icons.css';

在您的组件中:

import { Icon} from '@mui/material';

...

<Icon>{name}</Icon>

请注意图标名称是小写字母和下划线分隔


2
投票
import React, {createElement } from "react";
import * as MuiIcons from "@material-ui/icons";

export default ({ iconName }) => (
  <div>
      {createElement(MuiIcons[iconName])}
  </div>
);


<ComponentWithIcon iconName="Add" />
<ComponentWithIcon iconName="Anchor" />

1
投票

这是一个组件,允许您像这样从字符串创建组件

<MIcon name={'AccessAlarms'} sx={{ mr: 0.5 }}/>

打字稿中的组件:

import { IconTypeMap } from '@mui/material'
import * as MUIcon from '@mui/icons-material'

type IconProps = IconTypeMap['props']

interface MIconProps extends IconProps {
  name: string | undefined
}

export default function MIcon(props: MIconProps) {
  const { name } = props
  const Icon = MUIcon[name as keyof typeof MUIcon]
  if (Icon == null) {
    throw `There is no "${name}" Icon`
  }
  return <Icon {...props} />
}

您可以从https://mui.com/material-ui/material-icons/

选择图标的名称

此组件中还提供其他通用图标道具,例如

sx


0
投票

如上面 thclark 的答案的评论中所述,使用 Icon 组件的解决方案将使用 Material-UI 图标的字体版本,该版本不包含完整的图标集。

通过使用相同的方法来获取正确的图标名称(借自 thclark)并结合 React.createElement 就可以了。我在 TypeScript 中做到了这一点,在普通 javascript 中甚至更容易。这里是 TS 版本的组件(dynamicIcon.tsx),也可以在 this repo:

import * as React from 'react';
import * as Icons from '@material-ui/icons/';

type IconType = typeof import('@material-ui/icons/index');

interface DynamicIconProps {
    iconName: string,
    className: string
}

function upperFirst(string:string) {
    return string.slice(0, 1).toUpperCase() + string.slice(1, string.length)
}
  
function fixIconNames(string:string) {
    const name = string.split('-').map(upperFirst).join('')
    if (name === '3dRotation') {
        return 'ThreeDRotation'
    } else if (name === '4k') {
        return 'FourK'
    } else if (name === '360') {
        return 'ThreeSixty'
    }
    return name;
}

export default class DynamicIcon extends React.Component<DynamicIconProps> {
    constructor(props: DynamicIconProps) {
        super(props);
    }

    render() {
        return React.createElement(Icons[fixIconNames(this.props.iconName)! as keyof IconType], {className: this.props.className});
    }
}

0
投票

从 @mui 导入整个图标,将我的构建大小增加了 4MB,这不是我想要的,所以最后我像这样解决了它

import Icon from "@material-ui/core/Icon";
import * as React from "react";



import { Props } from "./types";


function cameltoSnakeCase(text = "") {
    return text
        .replace(/([A-Z])/g, "_$1")
        .toLowerCase()
        .slice(1);
}


const IconPresentation = ({ glyph, sx }: Props) => {
    if (!glyph) return null;
    return <Icon style={{ ...sx }}>{cameltoSnakeCase(glyph?.toString())}</Icon>;
};


export default IconPresentation;

0
投票

你可以这样实现

import { SvgIconComponent } from '@mui/icons-material';

const MUIcon: { [key: string]: SvgIconComponent } = require('@mui/icons-material');

const CompA = () => {
  const renderIcon = (iconName: string) => {
    const Icon = MUIcon[iconName];

    return (
       {Icon && <Icon />}
    )
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.