在Vue中如何优雅的使用SVG

16,517 阅读2分钟

1.SVG在普通页面的使用

SVG指的是利用XML格式定义的图像,可以当做html标签被嵌入到网页中呈现某一种效果。

在网页中使用svg的实例:

<svg width="100" height="100" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <rect width="100%" height="100%" style="fill:blue;stroke-width:2;stroke:rgb(0,0,0)"/>
</svg>

2.在Vue中使用svg

vue项目中引入svg,虽然可以像网页一样把一大段代码拷贝进去,但是对于模块化开发来说却显得很臃肿,于是svg提供了use标签,这样可以把svg源码放在静态目录下,然后通过use标签来引用即可。

先来看一下svg的代码

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position: absolute; width: 0; height: 0" id="__SVG_SPRITE_NODE__">
    <symbol xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="icon" viewBox="0 0 1024 1024" id="one">
    <defs><style type="text/css"></style></defs>
    <rect width="100%" height="100%" style="fill:rgb(153, 238, 172);stroke-width:2;stroke:rgb(0,0,0)"></rect>    
    </symbol>
</svg>

使用方法:

<svg><use xlink:href="#one"></use></svg>
  • 注:symbol中的iduse中的href要对应才行。

我们进行项目开发时,一般都是需要使用webpack进行打包处理的。而处理非js文件,都是需要使用各种loader来进行加载处理。目前用来处理svg的就是svg-sprite-loader

高能提示:如果vue项目是使用ts写的,那么还需要在shims-vue.d.ts中增加如下代码:

declare module '*.svg'
{
  const content:string;
  export default content;
}

首先我们要先安装svg-sprite-loader; yarn add svg-sprite-loader -D

然后在vue.config.js中配置:

const path = require('path');

module.exports = {
	chainWebpack:(config)=>{
    const dir=path.resolve(__dirname,'存放.svg的文件夹路径');
    config.module.rule('svg-sprite').test(/\.svg$/).include.add(dir).end().use('svg-sprite-loader').loader('svg-sprite-loader').options({extract:false}).end()
    
    config.plugin('svg-sprite').use(require('svg-sprite-loader/plugin'), [{plainSprite: true}])
    config.module.rule('svg').exclude.add(dir) 
    }
}

这个时候我们就可以在项目中直接使用use标签引入icon了;

<svg><use xlink:href="#one"></use></svg>

3.封装一个Icon组件

如果项目中需要多次引用svg图标,我们就可以封装一个Icon组件,每次使用的时候就可以调用该组件,只要传入一个属性就可以拿到对应的svg

---Icon.vue---
<template>
    <svg>
        <use :xlink:href="'#'+name"></use>
    </svg>
</template>

<script lang="ts">
    const importAll = (requireContext:__WebpackModuleApi.RequireContext) => requireContext.keys().forEach(requireContext);
    try{importAll(require.context('../assets/icons',true,/\.svg$/));}catch(error){console.log(error);}
    export default {
        props:['name'],
        name:'Icon'
    };
</script>

为了方便呢全局使用Icon组件,我们可以在main.ts中引入该组件。

import Icon from '@/components/Icon.vue';
Vue.component('Icon',Icon)

这样子在其他组件就可以使用Icon组件了。

<Icon name='down'/>

4.关于svg无法修改颜色的解决方法。

有时候我们不小心下载了带有颜色的svg文件,那么修改svg的颜色可以直接打开svg文件,然后修改里面的fill属性即可。但是如果有很多个图片,而且多个地方用到同一个svg文件,恰好颜色需求不一样,这样子怎么解决呢。

这个时候我们可以使用svgo-loader进行处理了。

首先下载svgo-loader yarn add svgo-loader

然后再vue.config.js里面配置:

chainWebpack:(config)=>{
    const dir=path.resolve(__dirname,'src/assets/icons')
    config.module
      .rule('svg-sprite')
      .test(/\.svg$/)
      .include.add(dir).end() // 包含 icons 目录
      .use('svg-sprite-loader').loader('svg-sprite-loader').options({extract:false}).end()
      .use('svgo-loader').loader('svgo-loader')
      .tap(options=>({...options,plugins:[{removeAttrs:{attrs:'fill'}}]})).end()
        config.plugin('svg-sprite').use(require('svg-sprite-loader/plugin'), [{plainSprite: true}])
        config.module.rule('svg').exclude.add(dir) // 其他 svg loader 排除 icons 目录
  }
}

这样子我们再不同组件使用同一个svg文件,而且颜色不一样,我们可以在样式里面通过color来直接指定svg的颜色。

参考资料

SVG在Vue中如何引入?