Vue项目中使用svg图标

1,211 阅读1分钟

1. 安装依赖

npm install svg-sprite-loader --save-dev

2. 在vue.config.js中配置

const path = require('path')
const webpack = require('webpack')

module.exports = {  
  chainWebpack: (config) => {    
    //配置svg-sprite-loader    
    config.module      
      .rule('svg')      
      .exclude.add(path.resolve('src/icons'))      
      .end();    
    config.module      
      .rule('svg-sprite-loader')      
      .test(/\.svg$/)      
      .include      
      .add(path.resolve('./src/icons')) //处理svg目录      
      .end()      
      .use('svg-sprite-loader')      
      .loader('svg-sprite-loader')      
      .options({        
        symbolId: 'icon-[name]'      
      })  
   },
}

3. 在components中创建svgIcon组件

<template>  
    <i :class="['svg-icon', `svg-icon-${iconClass}`, className]" :style="svgStyle">    
        <svg fill="currentColor" aria-hidden="true" width="1em" height="1em">      
            <use :xlink:href="iconName" />    
        </svg>  
    </i>
</template>
<script>
export default {  
    name: "SvgIcon",  
    props: {    
        iconClass: {      
            type: String,      
            required: true    
        },    
        className: {      
            type: String    
        },    
        color: {      
            type: String    
        },    
        size: {      
            type: Number    
        }  
    },  
    computed: {    
        iconName() {      
            return `#icon-${this.iconClass}`;    
        },    
        svgClass() {      
            if (this.className) {        
                return `${this.className}`;      
            }      
            return "";    
        },    
        svgStyle() {      
            const { color, size } = this;      
            const style = {};      
            color && (style.color = color);      
            size && (style.fontSize = `${size}px`);      
            return style;    
        }  
    }
};
</script>
<style scoped>
.svg-icon {  
    vertical-align: -0.125em;  
    line-height: 0;  
    display: inline-block;
}
</style>

4. 图片位置存放并渲染

在src下创建icons文件夹,在icons文件夹中创建svg文件夹,把需要用到的svg图放到该文件夹下;另外再在icons文件夹下创建index.js文件

// index.js代码
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon' // svg组件
Vue.component('svg-icon', SvgIcon)

const requireAll = requireContext => requireContext.keys().map(requireContext)
const req = require.context('./svg', true, /\.svg$/)//这行代码就会去 svg 文件夹(不包含子目录)下找所有文件名以 .svg 结尾的文件能被 require 的文件。
// 我们通过正则匹配引入相应的文件模块。
// require.context有三个参数:
// directory:说明需要检索的目录
// useSubdirectories:是否检索子目录
// regExp: 匹配文件的正则表达式
requireAll(req)

5. 在main.js中全局引入svgIcon

import './icons/index.js' //引入svg

6. 在项目中使用

// 把下载到的.svg图放到icons/svg下
<div>
  <svg-icon iconClass="svgName" :size="60" color="orange" />
</div>

注意点:

有可能在使用的过程中会遇到svg单色图标设置color不生效的问题,上面vue组件的写法是使用currentColor的方式,svg会继承父元素的color值,但是前提是path或者g属性不能有fill和fill-rule属性,这会使currentColor无法生效,只需要手动删除fill属性

这样,设置color就没问题了

7. 项目图标预览

接下来还有一个比较需要解决的问题,就是本地图标预览,继续使用webpack-require-context方法,把本地图标名都拿到,再加载出来就可以啦

<script>
// 获取所有svg的名称
const icons = require  
.context("@/icons/svg", false, /\.svg$/)  
.keys()  
.map(name => name.replace(/^\.\/([\w-]+)\.svg/, "$1"));

export default {  
    name: 'SvgViewer',  
    methods: {    
        async handleIconClick(iconName) {      
            await navigator.clipboard.writeText(`<svg-icon iconClass='${iconName}' />`);      
            // alert(`${iconName}图标代码已复制到剪切板`);    
        }  
    },  
    render() {    
        const { SvgIcon } = this.$options.components;    
        return (      
            <div class="icon-view">        
            <p>点一点图标就能取代码</p>        
            {icons.map(iconName => (          
                <div class="icon" on-click={() => this.handleIconClick(iconName)}>            
                    <svg-icon iconClass={iconName} />            
                    <span class="icon-name">{iconName}</span>          
                </div>        
            ))}      
            </div>    
        );  
    },
}
</script>
<style lang="less" scoped>
.icon-view {  
    padding: 10px;  
    > p {    
        margin-bottom: 20px;    
        font-size: 20px;    
        text-align: center;  
    }  
    .icon {    
        display: inline-block;   
        width: 50px;    
        margin-right: 20px;    
        margin-bottom: 30px;    
        text-align: center;  
        cursor: pointer;  
        /deep/ svg {      
            display: block;      
            width: 40px;      
            height: 40px;    
        }    
        .icon-name {      
            display: block;      
            width: 100%;      
            .ellipsis1;    
        }  
    }
}
</style>

看看效果:

参考资料:

还在用字体图标吗,试试svg图标吧(内附vuecli-svg-sprite-loader插件)

vue项目中优雅的使用svg图