基本上,我想做的是导入一个SVG图标到我的react组件中,并添加一些道具。比如size="24px"
,使它作为一个组件更加灵活。或者通过添加className
道具,使它可以用CSS编辑(所以我可以添加hover prop)。由于这是我第一次使用TypeScript和Webpack,我对如何声明SVG元素的类型感到困惑,并得到一个错误(如下所示)
由于包含SVG的方法很多,因此我决定将其作为ReactComponent导入。
menu-icon.svg
<svg width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" fillRule="evenodd" d="M4.5 5h15a.5.5 0 1 1 0 1h-15a.5.5 0 0 1 0-1zm0 6h15a.5.5 0 1 1 0 1h-15a.5.5 0 1 1 0-1zm0 6h15a.5.5 0 1 1 0 1h-15a.5.5 0 1 1 0-1z"></path>
</svg>
header.tsx(这里我想要我的svg图标)
import React from 'react';
import MenuIcon from '../assets/menu-icon.svg';
const Header: React.SFC = () => {
return (
<header className="c-header u-side-paddings">
<MenuIcon className="c-header__icon" /> // <-- className prop doesn't match provided type
</header>
);
};
export default Header;
index.d.ts(因此.svg文件可以被视为一个组件)
declare module '*.svg' {
import React = require('react');
export const ReactComponent: React.SFC<React.SVGProps<SVGSVGElement>>;
const src: string;
export default src;
}
将className
属性添加到MenuIcon SVG组件会导致错误:
(JSX attribute) className: string
Type '{ className: string; }' is not assignable to type 'IntrinsicAttributes'.
Property 'className' does not exist on type 'IntrinsicAttributes'.ts(2322)
我目前的理解是
- 我可以将svg组件 Package 在一个div中,然后添加一个
className
,如下所示:<div className="c-header__icon"><MenuIcon/></div>
,但我觉得这是一个不优雅的解决方案,不是一个真正的好做法 - 我从this answer中了解到SVG属性不是字符串,因为它们是
SVGAnimatedString
对象。因此: - 我尝试创建.tsx文件而不是.svg文件(我不需要
index.d.ts
文件),但是它只在className
的类型是string
的情况下才起作用。而且我不确定将SVG图标存储在与.svg
不同的扩展名的文件中是否是一个好的做法。在我看来,这对清晰度没有好处。如果我错了,告诉我什么是真正的好做法,下面是一个例子:
import React from 'react';
interface MenuIcon {
className?: SVGAnimatedString;
}
export class MenuIcon extends React.PureComponent<MenuIcon> {
render() {
return (
<svg width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" fillRule="evenodd" d="M4.5 5h15a.5.5 0 1 1 0 1h-15a.5.5 0 0 1 0-1zm0
6h15a.5.5 0 1 1 0 1h-15a.5.5 0 1 1 0-1zm0 6h15a.5.5 0 1 1 0 1h-15a.5.5 0 1 1 0-1z"></path>
</svg>
);
}
}
我觉得我缺少一些基础知识,我真的很难弄清楚我应该关注什么,因为有几个主题组合在一起
5条答案
按热度按时间7hiiyaii1#
我一直面临着这个问题,这个解决方案对我来说很有效:
此外,我使用@svgr/webpack作为SVG加载器沿着使用Next.js
mum43rcc2#
您可以参数化svgs以轻松实现JSX。通过全局抽象实现元素级定制。如何实现?使用React的FC。尝试实现以下内容:
SvgIconConstituentValues
导入tsx文件{ FC }
从React导入同一tsx文件FC
和SvgIconConstituentValues
的SvgIcon
接口SvgIcon
的参数化来抽象SVG的属性,如下所示<svg>...</svg>
,属性为JSX.IntrinsicElements.svg: SVGProps<SVGSVGElement>
;(2)className 2为<circle />
属性JSX.IntrinsicElements.circle: SVGProps<SVGCircleElement>
;(3)className 3为<path />
的属性JSX.IntrinsicElements.path:SVGP属性。const ArIcon: SvgIcon = ({ ... }): JSX.Element => {...}
实际上是一个JSX. Element。因此,<svg></svg>
本身和任何子元素(圆圈、路径等)都是JSX.IntrinsicElements
,每个子元素都允许有自己唯一的className
。这些className
调用被手动添加到svg中,就像transform调用一样(在其他地方旋转内联图标)。JSX.IntrinsicElements
的JSX Attribute
类名定义如下use-dark-mode
)和依赖于屏幕宽度的图标渲染(@artsy/fresnel
)配合使用。您可以全局导入此图标,并在每个JSX.Element中内联调用参数,而无需传递任何属性fill-primary
调用是为.dark-mode
和.light-mode
css类定义的css变量,然后将其传递给:root
,并在客户端(onChange={darkMode.toggle}
)切换darkMode时激活。onClick={darkMode.enable}
触发图标改变其fillColor和strokeColor值作为css变量的函数。利用React的FC
通过抽象来参数化道具,产生了真正显著的粒度控制。在JSX.Element级别使用内联调用来全局定制SVG从未如此无缝。干杯
wgx48brx3#
这在使用Next.js的情况下是有效的
kx1ctssn4#
这一条对我很有效:
加布里埃尔回答https://stackoverflow.com/a/65326058/11313928缺少
ref
属性。7xzttuei5#
由于NextJS覆盖了我自定义的.d.ts导出的
*.svg
模块,我最终将所有svg文件导入到一个Icons.ts
文件中,并按如下方式键入它们:然后,当我想要使用一个图标时,我可以按如下方式导入它,intellisense会拾取svg prop值。
不是默认配置,但它工作!