Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

antd 自定义 Icon 的几种方式及其优劣 #33

Open
brickspert opened this issue Dec 8, 2019 · 3 comments
Open

antd 自定义 Icon 的几种方式及其优劣 #33

brickspert opened this issue Dec 8, 2019 · 3 comments

Comments

@brickspert
Copy link
Owner

brickspert commented Dec 8, 2019

虽然 antd 提供了大量的 Icon 图标,但是在平时的设计稿中,会出现各种设计师自定义的 Icon,对于这类图标,怎样处理更好呢?

多种方法

直接当做图片使用

svg 也是一种图片,可以作为 imgsrc 使用。

通过配置 url-loader 的配置,我们可以直接引用 svg 资源。

{
    test: /\.(png|jpg|gif|svg)$/,
    use: [{
        loader: 'url-loader',
        options: {
            limit: 8192
        }
    }]
}
import customSvg from '../assets/images/xxx.svg';

<img src={customSvg} />  

优劣

  • ✅快,无脑,无理解成本。
  • ❌不能像自带的 Icon 一样,设置 colorfont-size 等。

自定义 font 图标

参见官方文档

在 antd v3.9.0 之后,提供了一个 createFromIconfontCN 方法,方便开发者调用在 iconfont.cn 上自行管理的图标。

首先你需要在 iconfont 上创建自己的图标库,并上传自定义的 Icon,然后就可以通过自定义组件使用了。

iconfont 图标库

iconfont 上新建图标库比较简单,我就不赘述了。我讲一下在上传自定义 Icon 时的几个坑。

Q:自定义 SVG 上传后,显示为空白。

如果 SVG 图标不是封闭的,上传到 iconfont 之后,会显示为空白。那什么是封闭呢?大概就是图标有缺口~

比如下面的线条就是非封闭的,上传到 iconfont 就变成空白了。

1
2

我们只需要选中该图标,进行“轮廓化”处理即可。

3

Q:自定义 SVG 上传后,图标显示不全。

如果 SVG 图标由多个部分组成,但是没有进行“轮廓化”,那上传到 iconfont 之后,可能会显示不全。比如下图的图标,上传到 iconfont 后,图标显示不全了。

4
5

我们选中该图标多个部分,进行“轮廓化”即可。

6

**Q:自定义 SVG 上传后,无法通过 color 属性设置颜色。

我们从 sketch 导出的 svg,一般都是自带颜色的,我们在上传时,选择去除颜色并提交即可。

7

自定义 MyIcon 组件

经过上面的步骤,我们已经把需要的 Icon 上传到 iconfont 了,同时我们可以拿到字体的链接。

8

然后通过 antd 的 createFromIconfontCN 包装下即可使用。

const MyIcon = Icon.createFromIconfontCN({
  scriptUrl: '//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js', // 在 iconfont.cn 上生成
});

/* 使用起来还比较简单 */
<MyIcon type="xxx"/>

优劣

  • ✅如果只管使用 MyIcon,而不管维护,那是比较爽的。
  • ❌维护很麻烦!每次上传一个新图标,字体链接都会变化一次,组件中就得替换一下,烦不胜烦啊。
  • ❌由于是通过字体包引用进来的,无法做到按需加载。

自定义 SVG 图标

通过 svgr 我们可以将一个普通的 svg 图片,转成 React 组件。

通过 webpack 将 SVG 转成组件

参见官方文档

// webpack.config.js
// umijs 配置见 https://github.com/umijs/umi/issues/1078
{
  test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
  use: [
    {
      loader: 'babel-loader',
    },
    {
      loader: '@svgr/webpack',
      options: {
        babel: false,
        icon: true,
      },
    },
  ],
}
import { Icon } from 'antd';
import MessageSvg from 'path/to/message.svg'; // path to your '*.svg' file.

ReactDOM.render(<Icon component={MessageSvg} />, mountNode);

对于带颜色的图标,loader 并不知道 svg 上哪个颜色是需要自定义的,所以需要手动将 svg 中写死的 color 值改成 currentColor

9

优劣
  • ✅配置完 webpack 后,使用真的很简单。
  • ❌对于带颜色的 SVG 图标,需要手动去 svg 文件中改下 currentColor。

通过 cli 将 SVG 转成组件

svgr 可以通过 cli,将 SVG 转换为组件,同时可以将 svg 中的颜色,设置成变量。

正常情况下,我们导出的 SVG 长这样:

<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <!-- Generator: Sketch 58 (84663) - https://sketch.com -->
    <title>Group</title>
    <desc>Created with Sketch.</desc>
    <g id="组件" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <g id="一级导航" transform="translate(-1197.000000, -18.000000)">
            <g id="Group" transform="translate(1197.000000, 18.000000)">
                <circle id="Oval" fill="#2F54EB" cx="10" cy="10" r="10"></circle>
                <g id="plus" transform="translate(3.000000, 3.000000)" fill-rule="nonzero">
                    <rect id="Rectangle-path" fill="#000000" opacity="0" x="0" y="0" width="14" height="14"></rect>
                    <path d="M11.59375,6.48046875 L7.51953125,6.48046875 L7.51953125,2.078125 L6.48046875,2.078125 L6.48046875,6.48046875 L2.40625,6.48046875 C2.34609375,6.48046875 2.296875,6.5296875 2.296875,6.58984375 L2.296875,7.41015625 C2.296875,7.4703125 2.34609375,7.51953125 2.40625,7.51953125 L6.48046875,7.51953125 L6.48046875,11.921875 L7.51953125,11.921875 L7.51953125,7.51953125 L11.59375,7.51953125 C11.6539063,7.51953125 11.703125,7.4703125 11.703125,7.41015625 L11.703125,6.58984375 C11.703125,6.5296875 11.6539063,6.48046875 11.59375,6.48046875 Z" id="Shape" fill="#FFFFFF"></path>
                </g>
            </g>
        </g>
    </g>
</svg>

通过 svgr 的命令行尝试转一下:

npx @svgr/cli --icon --replace-attr-values "#2F54EB=currentColor" message.svg

输出结果为:

import React from "react";

const MessageSvg = props => (
  <svg width="1em" height="1em" viewBox="0 0 20 20" {...props}>
    <g fill="none" fillRule="evenodd">
      <circle fill="currentColor" cx={10} cy={10} r={10} />
      <path
        d="M14.594 9.48H10.52V5.078H9.48V9.48H5.406a.11.11 0 00-.11.11v.82c0 .06.05.11.11.11H9.48v4.402h1.04V10.52h4.074c.06 0 .11-.05.11-.11v-.82a.11.11 0 00-.11-.11z"
        fill="#FFF"
        fillRule="nonzero"
      />
    </g>
  </svg>
);

export default MessageSvg;

good job~ 现在我们获得了一个纯 React 组件,直接使用即可。

import { Icon } from 'antd';
import MessageSvg from './MessageSvg';

ReactDOM.render(<Icon component={MessageSvg} />, mountNode);
优劣
  • ✅可以满足功能需要,获得一个可以自定义颜色的 Icon。
  • ❌项目中不是维护 svg 图片,而是维护转换过后的 React 组件。

总结

上面的几种方案我有在多个项目中尝试过,目前觉得 通过 webpack 将 SVG 转成组件 方案不错。

  • 首先可以满足需求,与 antd 原生 Icon 使用无差异,可以通过 colorfont-size 等属性控制样式。
  • 使用简单,配置完 webpack 之后,就变成傻瓜式操作了。
  • 可以按需加载。
  • 不依赖第三方,比如 iconfont。

❤️感谢大家

关注公众号「前端技术砖家」,拉你进交流群,大家一起共同交流和进步。

image

@YoungHearts
Copy link

图标集成,也想用字体的方式,但是每次都追求速度,经常用的图片。作者的教程让我少了很多弯路,值得一看

@dmwin72015
Copy link

怎么封装成一个独立的组件库呢

@huangliangb0
Copy link

请问一下,用craco工具怎么配置呢?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants