在 React 中使用 SVG 图标组件

SVG 很酷,它们能放大放小。

那么 SVG 的优点是什么?

SVG 或可缩放矢量图形是基于 XML 的格式图像格式,可以在保持图像质量的同时缩放到任何大小。因此,当你需要根据需要调整大小的图像时,SVG 是可行的方法。它们基本上是 XML 文档,因此与其他图像格式相比,它们的文件大小也很小。

它们也是有效的 XML 元素,可以使用 CSS 进行操作。所以在 SVG 上改变颜色和笔画都可以通过 CSS 完成。

听起来不错。不好的地方呢?

在图像方面,SVG 非常适合简单的形状,充满基本的笔触和颜色。虽然比图标更复杂但它们不值得麻烦。(除非你正在进行数据可视化,否则请使用 D3.js

自己构建 SVG 也更复杂。由于它们是以 XML 格式构建的,因此构建一个可能比存储像素数据的等效光栅图像更难。

file

怎样在 React 中引入?

在 web 文档中使用 SVG 时,你有两种选择。按原样呈现 SVG 文档,或将其用作 img 标签中的 src 属性。优选的选项是按原样使用它,因为图像标记中的 SVG 呈现为图像,并且不能在 img 标签的 css 样式之外进行操作。

因此,在决定在 React 项目中使用 SVG 时,最好构建一个组件,而不是将 SVG 渲染到文档中。

const SVG = () => 
  <svg
    width="100%"
    height="100%"
    viewBox="0 0 32 32"
    xmlns="http://www.w3.org/2000/svg"
    xmlnsXlink="http://www.w3.org/1999/xlink"
  >
      <path d="some path here" file="#000" />
  </svg>

这会将静态 SVG 呈现到 html 文档中。让我们添加一些道具。

const SVG = ({
  style = {},
  fill = '#fff',
  width = '100%',
  className = '',
  height = '100%',
  viewBox = '0 0 32 32',
}) =>
  <svg
    width={width}
    style={style}
    height={height}
    viewBox={viewBox}
    className={className}
    xmlns="http://www.w3.org/2000/svg"
    xmlnsXlink="htpp://www.w3.org/1999/xlink"
  >
      <path d="some path here" fill={fill} />
  </svg>

我们现在可以使用此组件来呈现不同颜色,类名和样式的 SVG。

演示 https://codesandbox.io/embed/q79o54pxmj

当我们有多个图标来处理时怎么办?

好的,我们现在大致了解如何为 SVG 图标创建 React 组件。那么我们如何处理大量的图标,这在大型项目中很常见?在这里,我们有多种选择。我们可以有一个巨大的组件,它返回所需的 SVG 图标或创建一个映射器组件,它接收一个 prop 并将其映射到等效的 SVG 组件。

让我们来看看它们是如何实现的。

途径 #1

演示:https://codesandbox.io/embed/ryy418r5km

TL:DR:我们创建一个 SVG 组件并将名称 prop 传递给它。该组件解析与该图标关联的 viewBox 和路径值,并返回 SVG 元素。

让我们首先将名称 prop 添加到我们的 SVG 组件并解析该名称 prop 的路径。

const getPath = (name, props) => {
  switch(name) {
    case 'icon-1':
      return <path {...props} d="icon-1-path" />;
    case 'icon-2':
      return <path {...props} d="icon-2-path" />;
    default:
      return <path />
  }
}

const SVG = ({
  name = '',
  style = {},
  fill = '#000',
  width= '100%',
  className = '',
  height = '100%',
  viewBox = '0 0 32 32',
}) =>
  <svg
    width={width}
    style={style}
    height={height}
    viewBox={viewBox}
    className={className}
    xmlns="http://www.w3.org/2000/svg"
    xmlnsXlink="http://www.w3.org/1999/xlink"
  >
    {getPath(name, { fill })}
  </svg>;

效果很好。但我们没有考虑过每个 SVG 图标都有自己的 viewBox 值。所以我们还需要根据名称 prop 解析 viewBox。

const getViewBox = name => {
  switch(name) {
    case 'icon-1':
      return 'icon-1-view-box';  // Eg. 0 0 32 32
    default:
      return '';
  }
}

<svg
  width={width}
  style={style}
  height={height}
  className={className}
  viewBox={getViewBox(name)}
  xmlns="http://www.w3.org/2000/svg"
  xmlnsXlink="http://www.w3.org/1999/xlink"
>
    {getPath(name, { fill })}
</svg>;

就是这样。我们可以向此组件添加更多路径和视图框,并通过为我们需要的图标添加名称 prop 来使用它。

<SVG fill="#49c" width={100} name="icon-1" />

途径 #2

演示:https://codesandbox.io/embed/vvzkzwvp10

TR;DR:我们为每个 SVG 图标创建单独的文件,并创建一个索引文件,该文件根据名称 prop 返回 SVG 组件。

我们为每个我们想要的 SVG 图标创建单独的组件。

./icons
--/Phone.js
--/Trash.js
--/Messages.js
--/Envelope.js
--/Wifi.js

每个组件彼此独立,可以单独使用。

import Phone from './icons/Phone'

<Phone width={100} />

然后,我们创建一个索引文件,该文件根据名称 prop 返回组件本身。

./icons
--/Phone.js
--/Trash.js
--/Message.js
--/Envelope.js
--/Wifi.js
--/...
--/index.js

索引文件看起来像这样。

import React from 'react';

import Phone from './Phone';
import Messages from './Messages';

const Icon = props => {
  swtich(props.name) {
    case "phone":
      return <Phone {...props} />;
    case "messages":
      return <Messages {...props} />;
    default:
      return <div />;
  }
}

export default Icon;

因此,只要我们需要在混合中添加新图标,我们就会创建新组件并将它们包含在索引文件中。我们通过导入单个 Icon 组件并将名称 prop 发送到其中来使用此组件。

import Icon from './icons';

<Icon fill="#49c" width={100} name="phone" />

就是这样。我详细介绍来一些创建 React 组件来操作 SVG 图像的方法。当然,这些并不是 React 应用程序中处理 SVG 的唯一方法,也不是最好的方法。就像 Javascript 世界中的任何东西一样,我们总能提供其他选择。

替代选项

Webpack SVG Loader —— 用于将 SVG 文件作为组件导入的 webpack 加载程序

React Inline SVG —— 一个 React 组件,它将 SVG 文件路径作为 prop 在文档上呈现它们。

原文:https://blog.lftechnology.com/using-svg-ic...
图标资源:https://iconstore.co/

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!