【问题标题】:React Icon component with SVG's使用 SVG 的 React Icon 组件
【发布时间】:2021-06-06 00:03:48
【问题描述】:

我有一个文件夹名称icons,其中包含很多 SVG 文件。每个文件都是一个独立的图标,看起来像这样:

icons/heart.svg(我想避免将其转换为 JS)

<svg height="24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M22.178 13.583l-9.131 8.992a1.502 1.502 0 0 1-2.094 0l-9.131-8.992a6.192 6.192 0 0 1 0-8.773c2.439-2.413 6.395-2.413 8.834 0L12 6.154l1.344-1.344c2.439-2.413 6.395-2.413 8.834 0a6.192 6.192 0 0 1 0 8.773"/></svg>

我想创建一个组件,该组件将根据其名称加载 svg。

components/Icon.js

export const Icon = ({ name, ...props }) => {
  return (
    <svg height="24" width="24" viewBox="0 0 24 24" role="img">
      <path d={name} />
    </svg>
  );
};

我寻找的用法示例:(App.js)

<Icon name="heart" />  // should load heart.svg
<Icon name="star" /> // should load star.svg

【问题讨论】:

    标签: reactjs svg icons


    【解决方案1】:

    您可以创建一个导出所有 svg 文件的文件,并为每个文件命名。

    import heart from './icons/heart.svg'
    
    export { heart };
    

    然后你可以根据名字将你的图标导入到任何你想要的地方;

    import { heart } from './<path_of_above_file>'
    

    如果你想创建一个 Icon 组件然后创建一个组件并在其中渲染图标。

    export const Icon = ({ icon, ...props }) => {
      return (
       <div {...props}>
         {icon}
       </div>
      );
    };
    

    然后在任何你喜欢的地方使用它。

    import { heart } from './path_of_above_file';
    <Icon icon={heart} />
    

    另一种解决方案是将路径作为道具传递;

    export const Icon = ({ path, ...props }) => {
      return (
        <svg {...props} viewBox="0 0 24 24" role="img">
          <path d={path} />
        </svg>
      );
    };
    

    并使用传递路径的图标作为道具。

    <Icon path='M22.178 13.583l-9.131 8.992a1.502 1.502 0 0 1-2.094 0l-9.131-8.992a6.192 6.192 0 0 1 0-8.773c2.439-2.413 6.395-2.413 8.834 0L12 6.154l1.344-1.344c2.439-2.413 6.395-2.413 8.834 0a6.192 6.192 0 0 1 0 8.773' height="24" width="24" />
    

    【讨论】:

    • 这是一个很棒的方向,谢谢!最后一件事要关闭它 - 我可以用我自己的 &lt;svg&gt; 标签包装 {icon} 吗?所以我可以使用动态类名/大小/等
    • 您可以在包裹图标的 div 上设置类名和大小。
    • 是的,但我无法更改viewBox 或其他属性
    • 在这种情况下,您可以按照此处给出的说明进行操作css-tricks.com/creating-svg-icon-system-react
    • 我有点迷路了。它看起来不那么相关。再一次,我想使用你提出的系统,但我也想控制 &lt;svg&gt; 标签,而不是完全“扔”它(所以基本上,我想剥离 &lt;svg&gt; 标签
    【解决方案2】:

    您不必将 SVG 图标文件转换为 JS;它已经完成了。

    <svg-icon is=heart></svg-icon>
    <svg-icon is=heart fill="green" scale=".8"></svg-icon>
    <svg-icon is=heart fill="green" scale=".8" rotate="45"></svg-icon>
    <svg-icon is=smile></svg-icon>
    <svg-icon is=smile fill="gold" stroke="green" width="5"></svg-icon>
    

    但是.. 它是一个现代 W3C 标准 Web 组件 &lt;svg-icon is="heart"&gt;&lt;/svg-icon&gt;

    React doesn't comply with modern Web Standards 所以必须让它在 React 中工作。

    对于 IconMeister Web 组件:https://iconmeister.github.io/
    我将 7300+ 图标从主要图标集转换为 JSON 表示法:

    有了这个 JSON(注意你可以从不同的图标集中指定不同的 viewBoxes)

    { 
    "heart" : "box:36;fill:red;path:M33 8c-1-3-5-5-10-4A10 10 0 0018 8A10 10 0 0013 4C8 3 
               4 5 3 8c-2 4-1 8 2 13c3 4 7 7 12 12a1 1 0 001 0c5-5 9-8 12-12c4-5 4-9 3-13z",
    "smile": "box:128;fill:#000;path:M62 2C28 2 0 30 0 64s28 62 62 62s62-28 62-62S97 2 62 2z
              m0 112c-28 0-50-23-50-50S35 14 62 14s50 23 50 50s-23 50-50 50zm30-37c-3-3-7-2-9
              1c-6 7-13 10-21 10s-16-4-21-10c-3-3-6-3-9-1c-3 3-3 6-1 9c8 9 19 15 31 15s23-6 
              31-15c3-3 2-7-1-9zM42 60c5 0 8-4 8-8s-4-8-8-8s-8 4-8 8s4 8 8 8zm40-15c-7 0-14 
              5-15 11c-1 3 3 5 5 3l3-3c4-4 12-4 16 0l3 3c3 2 6 0 5-3c-1-7-9-11-15-11z"
    }
    

    796 字节! &lt;svg-icon&gt; Web 组件使用标准 HTML 创建控制 SVG:

    <svg-icon is=heart></svg-icon>
    <svg-icon is=heart fill="green" scale=".8"></svg-icon>
    <svg-icon is=heart fill="green" scale=".8" rotate="45"></svg-icon>
    <svg-icon is=smile></svg-icon>
    <svg-icon is=smile fill="gold" stroke="green" width="5"></svg-icon>
    

    和风格:

    <style>
      svg-icon {
        display:inline-block;
        width:120px;
        background:lightgreen;
      }
    </style>
    

    输出:

    完整的 Web 组件代码:

    没有库、没有框架、没有外部 SVG 文件、没有依赖项

    文档和来源:https://iconmeister.github.io/

    <style>
      svg-icon {
        display:inline-block;
        width:120px;
        background:lightgreen;
      }
    </style>
    
    <svg-icon is=heart></svg-icon>
    <svg-icon is=heart fill="green" scale=".8"></svg-icon>
    <svg-icon is=heart fill="green" scale=".8" rotate="45"></svg-icon>
    <svg-icon is=smile></svg-icon>
    <svg-icon is=smile fill="gold" stroke="green" width="5"></svg-icon>
    
    <script>
    ((t,e={path:(t,e="")=>`<path d='${t}' ${e}/>`},i={stroke:"#000",rect:"<rect width='100%' height='100%' fill='{tile}' {border}/>",fill:"none",tile:"none",img:1,width:1,scale:1,opacity:1,is:"",border:"",filter:"",top:"",v1:"",v2:"",v3:"",box:9,rotate:0,xy:0,w:0,h:0,api:[t,e]})=>{customElements.define("svg-icon",class extends HTMLElement{static get observedAttributes(){return Object.keys(i)}attributeChangedCallback(){this.svg()}svg(s=this,r=s.A||Object.keys(s.A={...i}).map((t=>Object.defineProperty(s,t,{set:e=>s.setAttribute(t,e),get:()=>s.getAttribute(t)||getComputedStyle(s).getPropertyValue("--svg-icon-"+t).replace(/"/g,"").trim()||s.A[t]},e[t]=e=>(s.A[t]=e,"")))),l,a=(t[s.is]||"").split`;`.map((t=>([r,l]=t.trim().split`:`,e[r]?e[r].apply(s,l.split`,`):t))).join``,o=s.box/2,c=`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 ${s.w||s.box} ${s.h||s.box}' style='vertical-align:top'>${s.rect}<g stroke-width='{width}' stroke='{stroke}' fill='{fill}' opacity='{opacity}' filter='{filter}' transform='translate({xy}) matrix({scale} 0 0 {scale} ${o-o*s.scale} ${o-o*s.scale}) rotate({rotate} ${o} ${o})'>${a}</g>${s.top}</svg>`.replace(/{\s?([^{}\s]*)\s?}/g,((t,e)=>s[e]))){return s.innerHTML=1==s.img?`<img style='vertical-align:top' src="data:image/svg+xml,${c.replace(/#/g,"%23")}">`:c}})})(
    {"heart":"box:36;fill:red;path:M33 8c-1-3-5-5-10-4A10 10 0 0018 8A10 10 0 0013 4C8 3 4 5 3 8c-2 4-1 8 2 13c3 4 7 7 12 12a1 1 0 001 0c5-5 9-8 12-12c4-5 4-9 3-13z",
    "smile":"box:128;fill:#000;path:M62 2C28 2 0 30 0 64s28 62 62 62s62-28 62-62S97 2 62 2zm0 112c-28 0-50-23-50-50S35 14 62 14s50 23 50 50s-23 50-50 50zm30-37c-3-3-7-2-9 1c-6 7-13 10-21 10s-16-4-21-10c-3-3-6-3-9-1c-3 3-3 6-1 9c8 9 19 15 31 15s23-6 31-15c3-3 2-7-1-9zM42 60c5 0 8-4 8-8s-4-8-8-8s-8 4-8 8s4 8 8 8zm40-15c-7 0-14 5-15 11c-1 3 3 5 5 3l3-3c4-4 12-4 16 0l3 3c3 2 6 0 5-3c-1-7-9-11-15-11z"});
    </script>

    PS.源是未经许可的,我希望看到一个 796 字节 (GZipped) 的 React 版本

    【讨论】:

      【解决方案3】:

      您可以有一个对象将path 名称映射到它的值:

      const PATHS = {
        star: "M22.178 ...",
        heart: "A22.153 ...",
      };
      
      export const Icon = ({ name, ...props }) => {
        return (
          <svg height="24" width="24" viewBox="0 0 24 24" role="img">
            <path d={PATHS[name]} />
          </svg>
        );
      };
      

      【讨论】:

      猜你喜欢
      • 2021-04-23
      • 2021-05-18
      • 2019-04-18
      • 1970-01-01
      • 1970-01-01
      • 2018-05-09
      • 1970-01-01
      • 1970-01-01
      • 2018-10-09
      相关资源
      最近更新 更多