基本上,我想要做的是将一个SVG图标导入我的react组件,并向它添加道具。像size="24px"一样,使它作为一个组件更加灵活。或者通过添加className支柱使其可编辑(因此我可以向它添加悬浮支柱)。由于这是我第一次与Webpack一起使用TypeScript,所以我对如何声明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)我目前为止的理解
className:<div className="c-header__icon"><MenuIcon/></div>,但我觉得这是一个不雅的解决方案,并不是一个很好的实践。SVGAnimatedString对象。所以: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>
);
}
}我觉得我缺少一些基本的东西,只是我很难弄清楚我应该关注什么,因为有几个主题结合在一起
发布于 2020-12-16 15:15:49
我一直面临着这个问题,这个解决方案对我来说很好:
declare module "*.svg" {
import { ReactElement, SVGProps } from "react";
const content: (props: SVGProps<SVGElement>) => ReactElement;
export default content;
}
此外,我还使用@svgr/webpack作为SVG加载程序以及Next.js
发布于 2020-09-21 08:49:00
您可以通过全局抽象将svgs参数化,以便于JSX.Element级别的自定义。多么?使用React的FC。尝试实现以下功能:
interface SvgIconConstituentValues {
strokeColor?: string;
strokeWidth?: string;
strokeWidth2?: string;
strokeWidth3?: string;
strokeFill?: string;
fillColor?: string;
fillColor2?: string;
fillColor3?: string;
fillColor4?: string;
fillColor5?: string;
fillColor6?: string;
fillColor7?: string;
imageWidth?: string;
imageHeight?: string;
width?: string;
height?: string;
rotateCenter?: number;
className?: string;
className2?: string;
className3?: string;
className4?: string;
className5?: string;
}
export default SvgIconConstituentValues;SvgIconConstituentValues导入tsx文件{ FC }从React导入到相同的tsx文件中import { FC } from 'react';
import SvgIconConstituentValues from 'types/svg-icons';
// FC can be parameterized via AbstractionSvgIcon和SvgIconConstituentValues的FC接口export interface SvgIcon extends FC<SvgIconConstituentValues> {}SvgIcon参数化的svg的性质如下export const ArIcon: SvgIcon = ({
width = '8.0556vw',
height = '8.0556vw',
strokeColor = `stroke-current`,
strokeWidth = '2',
fillColor = 'none',
fillColor2 = `fill-primary`,
rotateCenter = 0,
className = ` antialiased w-svgIcon max-w-svgIcon`,
className2 = ` stroke-current`,
className3 = ` fill-primary`
}): JSX.Element => {
return (
<svg
width={width}
height={height}
viewBox='0 0 65 65'
fill={fillColor}
xmlns='http://www.w3.org/2000/svg'
className={className}
transform={`rotate(${rotateCenter}, 65, 65)`}
>
<circle
cx='32.5'
cy='32.5'
r='31.5'
stroke={strokeColor}
strokeWidth={strokeWidth}
className={className2}
/>
<path
d='M30.116 39H32.816L27.956 26.238H25.076L20.18 39H22.808L23.87 36.084H29.054L30.116 39ZM26.462 28.992L28.226 33.816H24.698L26.462 28.992ZM40.7482 39H43.5202L40.7842 33.78C42.4582 33.294 43.5022 31.944 43.5022 30.162C43.5022 27.948 41.9182 26.238 39.4342 26.238H34.4482V39H36.9502V34.086H38.2462L40.7482 39ZM36.9502 31.944V28.398H38.9662C40.2262 28.398 40.9642 29.1 40.9642 30.18C40.9642 31.224 40.2262 31.944 38.9662 31.944H36.9502Z'
fill={fillColor2}
className={className3}
/>
</svg>
);
};<svg>...</svg>,property JSX.IntrinsicElements.svg: SVGProps<SVGSVGElement>;(2) className2 for <circle /> property JSX.IntrinsicElements.circle: SVGProps<SVGCircleElement>;(3) className3表示<path /> property JSX.IntrinsicElements.path: SVGProps。const ArIcon: SvgIcon = ({ ... }): JSX.Element => {...}确实是一个JSX.Element。因此,<svg></svg>本身和任何子(圆圈、路径等)都是JSX.IntrinsicElements,每个子类都允许有自己独特的className。这些className调用是手动添加到svg中的,转换调用也是如此(在其他地方将图标内联旋转)。JSX Attribute className of JSX.IntrinsicElements定义如下SVGAttributes<T>.className?: string | undefineduse-dark-mode)和屏幕宽度相关的图标呈现(@artsy/fresnel)。您可以全局导入此图标并在每个JSX.Element内内联调用参数,而无需任何道具传递。import { ArIcon } from 'components/svg-icons';
import Link from 'next/link';
import { Media } from 'components/window-width';
import { Fragment } from 'react';
import DarkMode from 'components/lead-dark-mode';
const ArIconConditional = (): JSX.Element => {
const arIconXs: JSX.Element = (
<Media at='xs'>
<Link href='/'>
<a
className='container block pl-portfolio pt-portfolio justify-between mx-auto w-full min-w-full '
id='top'
aria-label='top'
>
<ArIcon width='18vw' height='18vw' className='transition-all transform translate-y-90'
className2='transition-all duration-1000 delay-200 transform' className3='text-secondary fill-secondary' />
</a>
</Link>
</Media>
);
const arIconSm: JSX.Element = (
<Media at='sm'>
<Link href='/'>
<a
className='container block pl-portfolio pt-portfolio justify-between mx-auto w-full min-w-full '
id='top'
aria-label='top'
>
<ArIcon width='15vw' height='15vw' className='' className2='' className3='' />
</a>
</Link>
</Media>
);
const arIconMd: JSX.Element = (
<Media at='md'>
<Link href='/'>
<a
className='container block pl-portfolio pt-portfolio justify-between mx-auto w-full min-w-full '
id='top'
aria-label='top'
>
<ArIcon width='12.5vw' height='12.5vw' className='' className2='' className3='' />
</a>
</Link>
</Media>
);
const arIconDesktop: JSX.Element = (
<Media greaterThan='md'>
<Link href='/'>
<a
className='container block pl-portfolio pt-portfolio justify-between mx-auto w-full min-w-full '
id='top'
aria-label='top'
>
<ArIcon width='10vw' height='10vw' className='' className2='' className3='' />
</a>
</Link>
</Media>
);
const ArIconsCoalesced = (): JSX.Element => (
<Fragment>
<div className='relative block justify-between lg:w-auto lg:static lg:block lg:justify-start transition-all w-full min-w-full col-span-5'>
{arIconXs}
{arIconSm}
{arIconMd}
{arIconDesktop}
</div>
</Fragment>
);
return (
<Fragment>
<div className='select-none relative z-1 justify-between pt-portfolioDivider navbar-expand-lg grid grid-cols-6 min-w-full w-full container overflow-y-hidden overflow-x-hidden transform'>
<ArIconsCoalesced />
<div className='pt-portfolio'>
<DarkMode />
</div>
</div>
</Fragment>
);
};
export default ArIconConditional;JSX.IntrinsicElement圈只在手机上脉冲呢?将顺风的animate-pulse添加到className2中,如下所示// ...
const arIconXs: JSX.Element = (
<Media at='xs'>
<Link href='/'>
<a
className='container block pl-portfolio pt-portfolio justify-between mx-auto w-full min-w-full '
id='top'
aria-label='top'
>
<ArIcon width='18vw' height='18vw' className='transition-all transform translate-y-90'
className2='transition-all duration-1000 delay-200 transform animate-pulse' className3='text-secondary fill-secondary' />
</a>
</Link>
</Media>
);
// ...fill-primary调用是为.dark-mode和.light-mode css类定义的css变量,这些类随后被传递给:root,并在客户端(onChange={darkMode.toggle})切换darkMode时激活。onClick={darkMode.enable}触发图标将其fillColor和strokeColor值更改为css变量的函数。利用React的FC通过抽象将道具参数化,产生了真正显著的粒度控制。在JSX.Element级别使用内联调用来定制SVG从来没有这么无缝过。


干杯
发布于 2022-04-13 21:19:55
这在使用Next.js的情况下有效。
declare module "*.svg" {
import {ReactElement, SVGProps} from "react";
const ReactComponent: (props: SVGProps<SVGElement>) => ReactElement;
export {ReactComponent}
}https://stackoverflow.com/questions/62715379
复制相似问题