网上已经有很多文章写了相似的例子,不过自己实践之后还是把过程记录下来,这样知识就是自己的了。
版本:@vue/cli 4.4.1
实现内容:1.vue载入svg 2.能够更改svg样式 3.svg无限旋转
1.使用的loader:svg-sprite-loader、svgo-loader
我们在vue.config.js
文件里找到chainWebpack
属性,添加如下代码:
chainWebpack: config => {
// ......
config.module
.rule('svg')
.exclude.add(resolve('src/assets/icons/svg'))
.end();
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/assets/icons/svg'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]',
})
.end();
// .......
2.需要安装的loader:svg-sprite-loader、svgo-loader
npm i svg-sprite-loader svgo-loader -D
3.引入svg图片
我们在src/assets
下新建icons文件夹,文件夹里再新建svg文件夹,将svg图片放至svg文件夹里。(具体路径可根据自己习惯配置)
4.统一引入svg图片
在src下新建icons文件夹,新建index.js文件(要注意路径的配置):
const req = require.context('@/assets/icons/svg/', false, /\.svg$/);
const requireAll = requireContext => requireContext.keys().map(requireContext);
requireAll(req);
5.在main.js中引入
import './icons';
6.在组件中使用
<svg>
<use xlink:href="#icon-XXX">use>
svg>
这样,我们就能在界面上看到svg图片了。
7.优化
但是这样子使用有点麻烦,我们希望能够像那些ui组件库一样,直接XX-icon标签就能使用,所以我们可以自定义一个组件.
在components文件夹下新建SvgIcon.vue文件:
<template>
<svg :class="svgClass" aria-hidden="true" v-on="$listeners">
<use :xlink:href="iconName"/>
svg>
template>
<script>
export default {
name: 'SvgIcon',
props: {
name: {
type: String,
required: true
},
className: {
type: String,
default: ''
}
},
computed: {
iconName() {
return `#icon-${this.name}`;
},
svgClass() {
if (this.className) {
return 'scoped-svg-icon ' + this.className;
} else {
return 'scoped-svg-icon';
}
}
}
};
script>
<style lang="less">
.scoped-svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
style>
然后我们在icons的index.js文件下引入icon组件:
import Vue from 'vue';
import SvgIcon from '@/components/SvgIcon';
Vue.component('svg-icon', SvgIcon);
const req = require.context('@/assets/icons/svg/', false, /\.svg$/);
const requireAll = requireContext => requireContext.keys().map(requireContext);
requireAll(req);
最后大功告成,在界面中使用:
<svg-icon name="copy">svg-icon>
8.继续优化
使用的时候发现,有时候我们无法修改svg图片的颜色,比如在icon-font网站上下载的svg图片颜色无法更改。此时我们需要删掉svg原有的path中的fill属性:
修改vue.config.js
为如下代码:
chainWebpack: config => {
// ......
config.module
.rule('svg')
.exclude.add(resolve('src/assets/icons/svg'))
.end();
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/assets/icons/svg'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]',
})
.end()
.before('svg-sprite-loader')
.use('svgo-loader')
.loader('svgo-loader')
.options({
plugins: [
{removeAttrs: {attrs: 'path:fill'}}
]
})
.end();
// .......
此时再去修改svg颜色,就能生效了。
它会去掉svg原有的颜色,默认为黑色。
9.添加功能
添加一个加载的动画图标功能,当传入spin属性为true时,我们就让图标无限旋转起来。修改SvgIcon.vue组件为:
<template>
<svg :class="`${svgClass} ${spin ? 'scoped-svg-animation' : ''}`" aria-hidden="true" v-on="$listeners">
<use :xlink:href="iconName"/>
svg>
template>
<script>
export default {
name: 'SvgIcon',
props: {
name: {
type: String,
required: true
},
className: {
type: String,
default: ''
},
// 是否旋转
spin: {
type: Boolean,
default: false
}
},
computed: {
iconName() {
return `#icon-${this.name}`;
},
svgClass() {
if (this.className) {
return 'scoped-svg-icon ' + this.className;
} else {
return 'scoped-svg-icon';
}
}
}
};
script>
<style lang="less">
.scoped-svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
&.scoped-svg-animation {
animation: rotate 2s linear infinite;
}
@keyframes rotate {
from{transform: rotate(0deg)}
to{transform: rotate(360deg)}
}
}
style>
至此一个小功能完成。
局限性:
1.当svg为色彩丰富的图标时,颜色达不到想要的效果
2.会清除掉原有的svg图颜色样式,不太友好