如何使用其蛇形名称动态加载图标(React,material-ui)

IT技术 reactjs icons material-design material-ui
2021-05-13 09:49:54

通常我会根据 material-ui 说明直接导入它们来使用 material-ui 图标

但是我有一个文本标签,它是实际的图标名称(如calendar_view_day),需要从中动态获取和呈现图标组件。

我怎么能这样:

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

代替:

render() {
  return (
    <CalendarViewDay color="primary" />  // Imported by name
  )
}
2个回答

好的,所以我大大地高估了这一点。

正确答案

原来material-ui包含一个图标组件,允许您执行此操作...并且它自己转换名称,因此接受蛇、帕斯卡和其他变体。请注意,正如评论中指出的那样,这将大大增加捆绑包的大小。如果您的包大小受到限制,您将不得不采用不同的方法从某个地方提供图标 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>
  )
}

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

通过使用相同的方法来获得正确的图标名称(从thclark借来),并结合 React.createElement 来解决这个问题。我在 TypeScript 中做到了这一点,在 vanilla javascript 中更容易。这是 TS 版本 (dynamicIcon.tsx) 中的组件,也可在此 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});
    }
}