ase*_*zak 4 svg typescript reactjs webpack
基本上,我想要做的是将一个 SVG 图标导入到我的 React 组件中并为其添加道具。喜欢size="24px"让它作为一个组件更灵活。或者通过添加className道具使其可使用 CSS 进行编辑(这样我就可以向它添加例如悬停道具)。由于这是我第一次在 Webpack 中使用 TypeScript,我对如何为 SVG 元素声明类型感到困惑,但出现错误(如下所示)
由于包含 SVG 的方法有很多种,我决定将其作为 ReactComponent 导入。
菜单图标.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>
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
将classNameprop添加到 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)
Run Code Online (Sandbox Code Playgroud)
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>
);
}
}
Run Code Online (Sandbox Code Playgroud)
我觉得我缺乏一些基础知识,我真的很难弄清楚我应该关注什么,因为有几个主题组合在一起
gen*_*ela 13
import React, { SVGProps } from 'react'
// SVGElement props
type TSVGElementProps = SVGProps<SVGSVGElement>
Run Code Online (Sandbox Code Playgroud)
您可以参数化 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;
Run Code Online (Sandbox Code Playgroud)
SvgIconConstituentValues到 tsx 文件中{ FC }到同一个 tsx 文件中import { FC } from 'react';
import SvgIconConstituentValues from 'types/svg-icons';
// FC can be parameterized via Abstraction
Run Code Online (Sandbox Code Playgroud)
SvgIcon的接口FCSvgIconConstituentValuesexport interface SvgIcon extends FC<SvgIconConstituentValues> {}
Run Code Online (Sandbox Code Playgroud)
SvgIcon如下所示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>
);
};
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,抽象出了三个独立的 className 参数(1, 2, 3): (1) className for <svg>...</svg>, property JSX.IntrinsicElements.svg: SVGProps<SVGSVGElement>;(2)<circle />属性的 className2 JSX.IntrinsicElements.circle: SVGProps<SVGCircleElement>;(3)<path />属性 JSX.IntrinsicElements.path 的 className3:SVGProps。
请注意,这const ArIcon: SvgIcon = ({ ... }): JSX.Element => {...}确实是一个 JSX.Element。因此,它<svg></svg>本身和任何子元素(圆、路径等)都是JSX.IntrinsicElements,每个都可以有自己独特的className。这些className调用是手动添加到 svg 中的,变换调用也是如此(在其他地方内嵌旋转图标)。
JSX Attribute的className定义JSX.IntrinsicElements如下
SVGAttributes<T>.className?: string | undefined
Run Code Online (Sandbox Code Playgroud)
每个 JSX.IntrinsicElement 都有权使用 className 属性。一个 svg 中有 100 条路径和一个圆?您可以拥有 102 个可通过抽象参数化的类名。
现在是最好的部分。以下内容来自我的投资组合中的一个文件,我修改了抽象 svg 参数,使其能够与深色模式切换 ( use-dark-mode) 和依赖于屏幕宽度的图标渲染 ( @artsy/fresnel) 很好地配合。您可以全局导入此 Icon 并在每个 JSX.Element 中内联调用参数,而无需传递任何 props
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;
Run Code Online (Sandbox Code Playgroud)
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>
);
// ...
Run Code Online (Sandbox Code Playgroud)
该调用是为和css 类 fill-primary定义的 css 变量,然后传递给客户端 ( ) 并在切换 darkMode 时激活。.dark-mode.light-mode:rootonChange={darkMode.toggle}
因此,onClick={darkMode.enable}触发图标根据 css 变量的函数更改其 fillColor 和 strokeColor 值。利用 ReactFC通过抽象参数化 props 可以产生真正非凡的粒度控制。在全局 JSX.Element 级别使用内联调用自定义 SVG 从未如此无缝。
黑暗模式.禁用


干杯
我一直面临这个问题,这个解决方案对我来说很好:
declare module "*.svg" {
import { ReactElement, SVGProps } from "react";
const content: (props: SVGProps<SVGElement>) => ReactElement;
export default content;
}Run Code Online (Sandbox Code Playgroud)
此外,我使用@svgr/webpack作为 SVG 加载器以及 Next.js
| 归档时间: |
|
| 查看次数: |
13996 次 |
| 最近记录: |