# 快速上手

# 介绍

svgicon 是一个名称

svgicon 是 SVG 图标组件和工具集,将 SVG 文件变成图标数据(vue)或者图标组件(react),让你可以愉快的在项目中使用 SVG 图标,无论你是使用 vue, react, vue3.x, taro 还是其他 js 框架。svgicon 包括了以下的 npm 包:

  • @yzfe/svgicon 根据传入的参数(props)生成 SVG 图标组件需要的数据
  • @yzfe/vue-svgicon 适用于 vue2.x 的 SVG 图标组件
  • @yzfe/vue3-svgicon 适用于 vue3.x 的 SVG 图标组件
  • @yzfe/react-svgicon 适用于 react 的 SVG 图标组件
  • @yzfe/taro-svgicon 适用于 taro 的 SVG 图标组件
  • @yzfe/svgicon-gen 根据 SVG 文件内容,生成图标数据(图标名称和处理过的 SVG 内容)
  • @yzfe/svgicon-loader 将 SVG 文件加载成图标数据(vue)或者 SVG 图标组件(react), 可以自定义生成的代码
  • vite-plugin-svgicon vite 插件,功能与 @yzfe/svgicon-loader 类似
  • @yzfe/svgicon-viewer 预览 SVG 图标
  • @yzfe/vue-cli-plugin-svgicon vue-cli 插件,可以快速的配置 svgicon
  • @yzfe/svgicon-polyfill SVG innerHTML 兼容(IE)

# Vue (2.x & 3.x)

# 安装

# 使用 vue-cli 插件 (推荐)

# 将会提示你填写 SVG 文件路径,全局注册的组件标签名称和 vue 的版本
vue add @yzfe/svgicon
1
2

如果已经安装了 @yzfe/vue-cli-plugin-svgicon, 但是没有调用到这个插件,你可以手动调用。

vue invoke @yzfe/svgicon
1

成功调用后,会自动添加必要的依赖和代码,另外还会生成 .vue-svgicon.config.js 文件,用来配置 @yzfe/svgicon-loader 和 webpack 别名,还有 transformAssetUrls 等。

demo/vue-demo/.vue-svgicon.config.js
const path = require('path')
const svgFilePaths = [
    '../../packages/assets/svg',
    '../../packages/assets/font-awesome',
    './src/assets/svg',
].map((v) => path.resolve(v))
const tagName = 'icon'

module.exports = {
    tagName,
    svgFilePath: svgFilePaths,
    svgoConfig: {},
    pathAlias: {
        '@icon': svgFilePaths[0],
        '@fa': svgFilePaths[1],
        '@assetsIcon': svgFilePaths[2],
    },
    transformAssetUrls: {
        [tagName]: ['data'],
    },
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 不使用 vue-cli 插件

使用 vue-cli,但是没有使用 @yzfe/vue-cli-plugin-svgicon.

# loader
yarn add @yzfe/svgicon-loader --dev
# core
yarn add @yzfe/svgicon

# 添加图标组件
yarn add @yzfe/vue-svgicon # vue2.x
# or
yarn add @yzfe/vue3-svgicon # vue3.x
1
2
3
4
5
6
7
8
9

配置 vue.config.js

const svgFilePath = 'svg file path (absolute path)'

{
    chainWebpack(config) {
        config.module
            .rule('vue-svgicon')
            .include.add(svgFilePath)
            .end()
            .test(/\.svg$/)
            .use('svgicon')
            .loader('@yzfe/svgicon-loader')
            .options({
                svgFilePath
            })

        config.module.rule('svg').exclude.add(svgFilePath).end()

        // 推荐配置 transformAssetUrls
        config.module
            .rule('vue')
            .use('vue-loader')
            .loader('vue-loader')
            .tap((opt) => {
                opt.transformAssetUrls = opt.transformAssetUrls || {}
                opt.transformAssetUrls['icon'] = ['data']
                return opt
            })

        // 推荐配置 alias
        config.resolve.alias.set('@icon', svgFilePath)
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

配置好 vue.config.js 之后,还需要在入口文件加上以下代码

// vue2.x
import { VueSvgIcon } from '@yzfe/vue-svgicon'
import '@yzfe/svgicon/lib/svgicon.css'

Vue.component('icon', VueSvgIcon)
1
2
3
4
5
// vue3.x
import { VueSvgIconPlugin } from '@yzfe/vue3-svgicon'
import '@yzfe/svgicon/lib/svgicon.css'

app.use(VueSvgIconPlugin, {tagName: 'icon'})
1
2
3
4
5

# 手动配置

Webpack 配置

{
    module: {
        rules: [
            {
                test: /\.svg$/,
                include: ['SVG 文件路径'],
                use: [
                    {
                        loader: '@yzfe/svgicon-loader',
                        options: {
                            svgFilePath: ['SVG 文件路径'],
                            svgoConfig: null // 自定义 svgo 配置
                        }
                    }
                ]
            },
            // Recommend config, transformAssetUrls
            {
                test: /\.vue$/,
                use: [
                    {
                        loader: 'vue-loader',
                        options: {
                            transformAssetUrls: {
                                ['标签名']: 'data' // 全局注册的标签名,默认是 icon
                            }
                        }
                    }
                ]
            }
        ]
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

其他配置可以参考:不使用-vue-cli-插件

# 使用

<template>
    <div>
        <icon :data="arrowData" />
    </div>
</template>
<script>
import arrowData from 'svgfilepath/arrow.svg'
export default {
    data() {
        return: {
            arrowData
        }
    }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

如果配置了 transformAssetUrls, 可以直接使用 svg 文件路径. 建议也配置 svg 文件路径的别名。

<template>
    <div>
        <!-- 这里假设配置了svg 文件路径的别名 @icon  -->
        <icon data="@icon/arrow.svg" />
    </div>
</template>
1
2
3
4
5
6

# React

# 安装

yarn add @yzfe/svgicon-loader  --dev
yarn add @yzfe/svgicon @yzfe/react-svgicon
1
2

Webpack 配置













 








{
    module: {
        rules: [
            {
                test: /\.svg$/,
                include: ['SVG 文件路径'],
                use: [
                    {
                        loader: '@yzfe/svgicon-loader',
                        options: {
                            svgFilePath: ['SVG 文件路径'],
                            svgoConfig: null, // 自定义 svgo 配置
                            component: 'react', // 生成 React 组件
                        }
                    }
                ]
            }
        ]
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
umijs 配置 demo
import { defineConfig } from 'umi'
import path from 'path'

const svgFilePath = [
    path.join(__dirname, '../../packages/assets/svg'),
    path.join(__dirname, '../../packages/assets/font-awesome'),
]

export default defineConfig({
    nodeModulesTransform: {
        type: 'none',
    },
    targets: {
        ie: 11,
    },
    routes: [{ path: '/', component: '@/pages/index' }],
    chainWebpack(config) {
        config.module
            .rule('vue-svgicon')
            .include.add(svgFilePath)
            .end()
            .test(/\.svg$/)
            .use('svgicon')
            .loader('@yzfe/svgicon-loader')
            .options({
                svgFilePath,
                component: 'react',
            })

        config.module.rule('svg').exclude.add(svgFilePath).end()

        config.resolve.alias.set('@icon', svgFilePath[0])
        config.resolve.alias.set('@fa', svgFilePath[1])
    },
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

引入 css

import '@yzfe/svgicon/lib/svgicon.css'
1

# 使用

import MySvgIcon from 'svg-path/mysvg.svg'

export default function FC() {
    return (
        <div>
            <MySvgIcon color="red" />
        </div>
    )
}
1
2
3
4
5
6
7
8
9

如果你是 typescript 用户,请配置 tsconfig(使用了别名) 和 typings

{
     "compilerOptions": {
        "paths": {
            "@icon": ["svg 图标路径"]
        },
    },
}
1
2
3
4
5
6
7
declare module '@icon/*' {
    import { ReactSvgIconFC } from '@yzfe/react-svgicon'
    const value: ReactSvgIconFC
    export = value
}
1
2
3
4
5

# Vite

doc: https://github.com/MMF-FE/svgicon/tree/master/packages/vite-plugin-svgicon (opens new window)

demo: https://github.com/Allenice/svgicon-vite-demo (opens new window)

# Taro

# 安装

yarn add @yzfe/svgicon-loader  --dev
yarn add @yzfe/svgicon @yzfe/taro-svgicon
1
2

conifg 配置













 
















// 小程序配置;mini
{
   ...mini, // ...h5
   webpackChain (chain, webpack) {
      chain.merge({
        module: {
          rule: {
            svgIcon: {
              test: /\.svg$/,
              include: svgFilePath,
              use: [{
                loader: "@yzfe/svgicon-loader",
                options: {
                  svgFilePath,
                  component: 'taro',
                }
              }]
            }
          }
        }
      })

      chain.module
      .rule('image')
      .exclude.add(svgFilePath)
      .end()
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
taro 配置 demo
import path from 'path'

const svgFilePath = [
    path.join(__dirname, '../../../packages/assets/svg'),
    path.join(__dirname, '../../../packages/assets/font-awesome'),
]

const config = {
    projectName: 'taro-demo',
    date: '2021-2-23',
    designWidth: 750,
    deviceRatio: {
        640: 2.34 / 2,
        750: 1,
        828: 1.81 / 2,
    },
    sourceRoot: 'src',
    outputRoot: 'dist',
    plugins: [],
    defineConstants: {},
    copy: {
        patterns: [],
        options: {},
    },
    alias: {
        '@': path.resolve(__dirname, '..', 'src'),
        '@icon': svgFilePath[0],
        '@fa': svgFilePath[1],
    },
    framework: 'react',
    mini: {
        postcss: {
            pxtransform: {
                enable: true,
                config: {},
            },
            url: {
                enable: true,
                config: {
                    limit: 1024, // 设定转换尺寸上限
                },
            },
            cssModules: {
                enable: true, // 默认为 false,如需使用 css modules 功能,则设为 true
                config: {
                    namingPattern: 'module', // 转换模式,取值为 global/module
                    generateScopedName: '[name]__[local]___[hash:base64:5]',
                },
            },
        },
        webpackChain(chain, webpack) {
            chain.merge({
                module: {
                    rule: {
                        svgIcon: {
                            test: /\.svg$/,
                            include: svgFilePath,
                            use: [
                                {
                                    loader: '@yzfe/svgicon-loader',
                                    options: {
                                        svgFilePath,
                                        component: 'taro',
                                    },
                                },
                            ],
                        },
                    },
                },
            })

            chain.module.rule('image').exclude.add(svgFilePath).end()
        },
    },
    h5: {
        publicPath: '/',
        staticDirectory: 'static',
        postcss: {
            autoprefixer: {
                enable: true,
                config: {},
            },
            cssModules: {
                enable: true, // 默认为 false,如需使用 css modules 功能,则设为 true
                config: {
                    namingPattern: 'module', // 转换模式,取值为 global/module
                    generateScopedName: '[name]__[local]___[hash:base64:5]',
                },
            },
        },
        esnextModules: ['taro-ui'],
        webpackChain(chain, webpack) {
            chain.merge({
                module: {
                    rule: {
                        svgIcon: {
                            test: /\.svg$/,
                            include: svgFilePath,
                            use: [
                                {
                                    loader: '@yzfe/svgicon-loader',
                                    options: {
                                        svgFilePath,
                                        component: 'taro',
                                    },
                                },
                            ],
                        },
                    },
                },
            })

            chain.module.rule('image').exclude.add(svgFilePath).end()
        },
    },
}

module.exports = function (merge) {
    if (process.env.NODE_ENV === 'development') {
        return merge({}, config, require('./dev'))
    }
    return merge({}, config, require('./prod'))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123

引入 css

import '@yzfe/svgicon/lib/svgicon.css'
1

# 使用

import MySvgIcon from 'svg-path/mysvg.svg'

export default function FC() {
    return (
        <div>
            <MySvgIcon color="red" />
        </div>
    )
}
1
2
3
4
5
6
7
8
9

如果你是 typescript 用户,请配置 tsconfig(使用了别名) 和 typings

{
     "compilerOptions": {
        "paths": {
            "@icon": ["svg 图标路径"]
        },
    },
}
1
2
3
4
5
6
7
declare module '@icon/*' {
    import { TaroSvgIconFC } from '@yzfe/taro-svgicon'
    const value: TaroSvgIconFC
    export = value
}
1
2
3
4
5

# 其他框架

其他 js 框架可以通过 @yzfe/svgicon 编写适用于其框架的图标组件,可以参考 @yzfe/react-svgicon.

@yzfe/react-svgicon
import React from 'react'
import {
    svgIcon,
    Props,
    Options,
    setOptions,
    getPropKeys,
    Icon,
    IconData,
} from '@yzfe/svgicon'

interface ComponentProps extends Props {
    [key: string]: unknown
}

class ReactSvgIcon extends React.PureComponent<ComponentProps> {
    public render(): JSX.Element {
        const props = this.props
        const result = svgIcon(props)
        const attrs: Record<string, unknown> = {}

        if (props) {
            const propsKeys = getPropKeys()
            for (const key in props) {
                if (propsKeys.indexOf(key as keyof Props) < 0) {
                    attrs[key] = props[key]
                }
            }
        }

        attrs.viewBox = result.box
        attrs.className = (attrs.className || '') + ` ${result.className}`
        attrs.style = {
            ...((attrs.style as Record<string, string>) || {}),
            ...result.style,
        }

        return (
            <svg
                {...attrs}
                dangerouslySetInnerHTML={{ __html: result.path }}
            ></svg>
        )
    }
}

/** SvgIcon function component, define in @yzfe/svgicon-loader compile */
interface ReactSvgIconFC extends React.FC<ComponentProps> {
    iconName: string
    iconData: IconData
}

export {
    ReactSvgIcon,
    ReactSvgIconFC,
    Props,
    Options,
    setOptions,
    Icon,
    IconData,
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61