如何使用它的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 的关系名称
除非明确指定,否则如何在默认情况下将 Spring Data JPA 从 camelCase 命名为 snake_case?