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

Posted

技术标签:

【中文标题】如何使用它的snake_case名称动态加载图标(React,material-ui)【英文标题】:How can I dynamically load an icon using its snake_case name (React, material-ui) 【发布时间】:2019-10-15 14:09:32 【问题描述】:

通常我会通过直接导入 per the material-ui instructions 来使用 material-ui 图标。

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

我该怎么做:

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

代替:

render() 
  return (
    <CalendarViewDay color="primary" />  // Imported by name
  )

【问题讨论】:

【参考方案1】:

好吧,所以我想太多了。

正确答案

原来material-ui 包含一个图标组件,可让您执行此操作……它会自行转换名称,因此接受蛇、帕斯卡和其他变体。 注意,正如 cmets 中所指出的,这将大大增加捆绑包的大小。如果您受到捆绑包大小的限制,则必须采用不同的方法从某个地方提供图标 SVG!

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

...

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

上一个答案(工作但大量矫枉过正)

创建函数到:

将蛇形大小写转换为 PascalCase 处理the material-ui icons documentation中报告的特殊情况

...然后使用material-ui图标组件。

代码如下:

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>
  )

【讨论】:

material-ui 导入整个 Icon 模块将解决该功能,但会爆炸包!您可以通过React official guideline 分析包大小 感谢@Navid,在我的回答中添加了健康警告。 此解决方案使用字体图标而不是 svg 图标。需要加载使用的字体。见:material-ui.com/components/icons/#icon-font-icons “正确答案”只为我打印字符串 props.iconName,不显示实际图标。 @jonasRosenvist,您还需要在代码中包含一些链接:fonts.googleapis.com/icon?family=Material+Icons" />【参考方案2】:

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

通过使用相同的方法来获得正确的图标名称(从 thclark 借用)结合 React.createElement 可以解决问题。我在 TypeScript 中做到了这一点,在 vanilla 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);
    

【讨论】:

提供 TS 解决方案做得很好。但是元素的创建从来都不是问题——它是包的大小。我不使用 TS,但据我所知,为了工作,这仍然必须将每个图标导入到包中(检查create-react-app.dev/docs/analyzing-the-bundle-size)。

以上是关于如何使用它的snake_case名称动态加载图标(React,material-ui)的主要内容,如果未能解决你的问题,请参考以下文章

从 camelCase 转换为 snake_case 的关系名称

如何动态加载material-ci-icons图标

除非明确指定,否则如何在默认情况下将 Spring Data JPA 从 camelCase 命名为 snake_case?

如何提取android手机所有app的icon图标

如何配置 Jackson 在 Micronaut 中使用 SNAKE_CASE?

如何使用动态链接库中的资源