如何在vue项目中引入svg图标
概述
svg,即Scalable Vector Graphics,可缩放矢量图形。
相对于jpg,png图标,svg可以在任意分辨率下保证不会模糊,即便是网页缩放了。
上图是知乎的截图,可以看到铃铛图标是svg的,消息数量是CSS写的,二者缩放到任意体积都可以保持一个同等的清晰度。
而且现在很多ui标注的软件都已经支持直接生成svg,比如sketch,那为何不尝试一下呢。
配置
svg是一种用xml描述的语言,也就是说,html中引入svg,是以嵌入xml的方式进行的。(也有其他的多种方式,比如img直接引入)
如上,比如circle标签表示圆,和html是很相似的,只是其用于描述各种图形。
基于此,在vue项目中,我们完全可以将上面的标签封装成一个组件。这样想用的地方直接引入就可以了。
<!-- svg-icon 组件 -->
<template>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" />
</svg>
</template>
似乎没什么问题,但我们的svg并非自己画出来的,而是ui大佬们给出的svg图标,所以这时候我们就需要svg中另一个标签 use
,这个标签的意思是以id的形式使用某个具体的svg, 比如:
<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
<circle id="myCircle" cx="5" cy="5" r="4" stroke="blue"/>
<use href="#myCircle" x="10" fill="blue"/>
</svg>
可以看出use相当于拷贝了一份新的出来,并且还可以覆盖原有的样式。
利用这样一个功能,我们就可以实现一个类似雪碧图的加载svg方式:
在页面中预先加载所有的svg,然后再需要的具体某个svg的地方使用id的方式定位到所需的具体的svg
这个思路不是我发明的,而是参考了以下:
Sprites are rendered and injected in pages automatically, you just refer to images via
这个正是svg-sprite-loader中的描述。也就是在webpack中实现引入svg图标所需要的loader。
好了,既然有这个思路,不妨改造一下上面写过的组件:
<template>
<svg v-on="$listeners">
<use :xlink:href="iconName" />
</svg>
</template>
<script>
export default {
name: 'SvgIcon',
props: {
iconName: {
type: String,
required: true,
}
},
....
在需要引入的地方引入:
<svg-icon iconName="my-svg-icon" />
并修改vue.config.js的配置
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')
.end();
}
简单说明一下以上的配置,vue-cli已经会处理svg了,但并不是以雪碧图的方式引入的。这里我们自己配置单独处理,所以先移除原有的规则,并添加自己的规则。
到这里,我们已经实现了自定义的组件,配置好了loader,但svg文件还没有引入的,我们希望的引入方式是全部引入(就像雪碧图),然后在页面加载时候加载,需要使用的地方直接标明ID即可。
所以还需要写一个加载所有svg文件的js文件,当然这里不希望挨个svg去import,而是自动的引入某一个文件夹下的所有svg文件。webpack恰恰提供了这样一个api require.context
,这里不详细介绍了,有兴趣的可以自行了解。只是放出最终的代码
import Vue from 'vue';
import SvgIcon from '@/components/svgIcon';
Vue.component('svg-icon', SvgIcon);
const req = require.context('./svg', false, /\.svg$/);
const requireAll = (requireContext) => requireContext.keys().map(requireContext);
requireAll(req);
简单说明一下,该文件配合svg-sprite-loader会生成一个以文件名为svg id的雪碧图。所以使用svg-icon
这个组件的时候,iconName应该与svg的文件名保持一致。当然这个可以配置,具体详见svg-sprite-loader的文档。
至此,所以需要的配置都以就绪,尽情页面中使用吧…
参考
https://www.npmjs.com/package/svg-sprite-loader
https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use
还没有评论,来说两句吧...