Vue项目引入使用svg
随着项目页面的增多,UI 库的 svg 图标渐渐不够用了。于是 UI 给了一大堆的 svg 新的图标,一个个引入显然不实际,于是把 svg 放到指定
文件夹,然后批量引入,通过组件去使用这一堆 svg。
# 项目结构
|--build
| `-- webpack.base.js
`--src
`-- assets
`-- icons
|-- index.js
`-- svg
`-- 全部的svg图标 `xxx.svg`
2
3
4
5
6
7
8
大概目录结构如下,因为是自己写的 webpack 配置,等下也会说 vue.config.js
该如何改造
所有的 svg 图标都在 assets/icons/svg
文件夹下。assets/icons/index.js
就是我们的引入的入口文件了
# 动态引入所有的 svg
- assets/icons/index.js
const requireAll = requireContext => requireContext.keys().map(requireContext)
const req = require.context('./svg', false, /\.svg$/)
requireAll(req)
2
3
4
index.js 的文件就是为了引入
./svg
目录下的所有.svg
文件,使用 requireAll 引入,就无须手动一个个引入了
# 创建组件,使用 svg
刚才的 svg 资源是在 assets 目录下的,接下来是新建组件,所以在 src/components
目录下,新建一个 SvgIcon.vue
的组件
- src/components/SvgIcon.vue
<template>
<svg class="svg-icon" aria-hidden="true" v-if="iconName">
<use :xlink:href="iconName" />
</svg>
</template>
<script>
import '../assets/icons/index'
export default {
name: 'SvgIcon',
props: {
name: {
default: '',
type: String
}
},
computed: {
iconName() {
let name = this.name
if (name) {
return `#icon-${name}`
} else {
return '#icon-icon'
}
}
}
}
</script>
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
留意看第 8 行的代码,引入对应的 js 文件。所以我们在注册组件时,自动会引入对应的 icon
留意 21 行的
#icon-${name}
稍后会解释到。
# 修改 webpack 配置
组件已经准备好了,可是 webpack 只认得 js 文件,所以我们还得找到对应支持 svg 的插件 svg-sprite-loader
npm i svg-sprite-loader -D
# 项目的 webpack 配置
如果是自定义的 webpack 配置,找到 module.rules
添加一项处理 svg:
- webpack.config.js
svgoConfig 是我项目自定义的内容,仅供参考,按需选配
其次,如果配置的 svg 与其他库有冲突(比如 iview),所以就配置只指定
/src/assets/icons
做转换,其余的都留给url-loader
处理既然 svg-sprite-loader 已经处理了指定的文件夹,那么
url-loader
就无须重复处理了 (这部分的配置理解为主,功能效果是一致的)如此一来,既可以处理项目原有的 svg 不受影响,新添加的 svg-icon 也有插件进行处理了。
var svgoConfig = JSON.stringify({
plugins: [
{ removeTitle: true },
{ convertColors: { shorthex: true } },
{ convertPathData: true },
{ cleanupAttrs: true },
{ removeComments: true },
{ removeDesc: true },
{ removeUselessDefs: true },
{ removeEmptyAttrs: true },
{ removeHiddenElems: true },
{ removeEmptyText: true }
]
})
module: {
rules: [
{
test: /.*\.svg$/,
loaders: [
{
loader: 'svg-sprite-loader',
options: {
symbolId: 'icon-[name]'
}
},
'svgo-loader?' + svgoConfig
],
include: [
// 处理不了 iview 的字体,所以只处理本地svg
resolve('/src/assets/icons')
]
},
{
test: /\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
publicPath: '../../',
limit: 10000,
name: utils.assetsPath('fonts/[name].[ext]?[hash:7]')
},
exclude: [resolve('/src/assets/icons')] // 已经交由 svg-sprite-loader 处理,就排除指定文件夹
}
]
}
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
# vue-cli 配置
vue-cli 配置文档 (opens new window)
同理,vue-cli 默认有处理 svg 的插件,所以先把 src/assets/icons
的排除
然后在经过 svg-sprite-loader 来配置处理图标
module.exports = {
chainWebpack(config) {
config.module
.rule('svg')
.exclude.add(resolve('src/assets/icons'))
.end()
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/assets/icons'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
.end()
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# icon-name 的玄机
可以看到无论是 webpack 配置还是 vue-cli 配置,在 options.symbolId 都有一段 icon-[name]
的配置。这段也是我们组件识别到底使用哪个 svg 的关键,所以这里的 icon-
需要和组件返回的 #icon-${name}
格式一致。
如果不想叫 icon-xxx
那么改动的话记得组件和 webpack 配置都得同步修改即可。
# 使用 svg 组件
引入组件的步骤就不写了。用法如下:
example 就是 svg 的文件名称,文件如下: assets/icons/svg/example.svg
<svg-icon name="example" />
这样就可以愉快的使用自定义的 svg 了。