如何在Vue项目中使用SVG Icon

栏目: JavaScript · 发布时间: 5年前

内容简介:Web中对于Icon的使用已经是非常频繁的一件事情了,而且很有图标的使用会让你的Web应用程序或Web网页面变得更具可交互性和可使用性。早前在《Web中的图标》一文中和大家一起探讨了如何在Web中使用图标。其中不同的使用方式都具有各自的优势,但随着技术的革新,其中SVG的图标在Web中的使用也越来越频繁,并且其具备的优势也越来越明显。正因如此,在自己的项目中使用SVG的图标的场景也越来越多,因此,今天想和大家一起聊聊如何在Vue的项目中更好的使用SVG图标。在Vue官方网站专门有一节内容,向大家介绍了如何在

Web中对于Icon的使用已经是非常频繁的一件事情了,而且很有图标的使用会让你的Web应用程序或Web网页面变得更具可交互性和可使用性。早前在《Web中的图标》一文中和大家一起探讨了如何在Web中使用图标。其中不同的使用方式都具有各自的优势,但随着技术的革新,其中SVG的图标在Web中的使用也越来越频繁,并且其具备的优势也越来越明显。正因如此,在自己的项目中使用SVG的图标的场景也越来越多,因此,今天想和大家一起聊聊如何在Vue的项目中更好的使用SVG图标。

单个Icon组件的使用

在Vue官方网站专门有一节内容,向大家介绍了如何在项目中更好的使用SVG图标系统,而且这个系统是可具编辑的。先来看最基础的一个示例,这个示例是基于Vue CLI3的基础上构建的。通过官网提供的命令,使用CLI命令创建一个Vue项目,比如:

vue create svg-icon-app

采用默认的模板来构建了一个 svg-icon-app 项目。我们先跟着官网提供的思路来一步一步往下走,在 components 目录下创建一个新的目录 icons 。并将相应的SVG图标以一种标准化的方式命名,比如:

components/icons/IconBox.vue
components/icons/Facebook.vue
components/icons/Twitter.vue
components/icons/GooglePlus.vue

其中 IconBox.vue 是SVG图标的一个基础图标组件,在这个组件中使用了 slot ,其模板如下:

<!-- IconBox.vue -->
<template>
    <svg xmlns="http://www.w3.org/2000/svg"
        :width="width"
        :height="height"
        viewBox="0 0 18 18"
        :aria-labelledby="iconName"
        role="presentation"
    >
        <title
            :id="iconName"
            lang="en"
        >{{ iconName }} icon</title>
        <g :fill="iconColor">
            <slot />
        </g>
    </svg>
</template>

你可以像上面这样使用这个基础图标,唯一可能要做的就是根据你图标的 viewBox 来更新其 viewBox 。在基础图标组件里会有 widthheighticonColor 以及 iconNameprops ,这样我们就可以通过 props 对其动态更新。 iconName 将会同时用在 <title> 的内容及其用于提供可访问性的 id 上。

<!-- IconBox.vue -->
<script>
    export default {
        name: 'IconBox',
        props: {
            iconName: {
                type: String,
                default: 'box'
            },
            width: {
                type: [Number, String],
                default: 32
            },
            height: {
                type: [Number, String],
                default: 32
            },
            iconColor: {
                type: String,
                default: 'currentColor'
            }
        },
        data () {
            return {

            }
        }
    }
</script>

currentColor 会成为 fill 的默认值,于是图标就会继承 color 的值( currentColor 是CSS的一个很优秀的属性)。我们也可以根据需求传递一个不一样的颜色值。

特别声明, viewBox 是SVG中的一个重要的概念,如果你从未接触过的话,建议你花点时间对该概念进行了解。你可以点击这里、或这里、还有这里进行了解。

IconBox 组件完成了之后,接下来把对应的图标组件完善。

示例中的几个图标,都来自于 Font Awesome 提供的SVG图标。

如何在Vue项目中使用SVG Icon

除此之外,还可以通过 iconmonstrIcoMoon 平台,甚至还可以使用 NucleoApp 来获取SVG图标。特别是NucleoApp来管理你的SVG图标:

如何在Vue项目中使用SVG Icon

我们通过编辑器打开其中一个 .svg 文件,比如 facebook.svg ,其代码会是这样的:

<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="facebook-square" class="svg-inline--fa fa-facebook-square fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
    <path d="M29,0 L3,0 C1.35,0 0,1.35 0,3 L0,29 C0,30.65 1.35,32 3,32 L16,32 L16,18 L12,18 L12,14 L16,14 L16,12 C16,8.69375 18.69375,6 22,6 L26,6 L26,10 L22,10 C20.9,10 20,10.9 20,12 L20,14 L26,14 L25,18 L20,18 L20,32 L29,32 C30.65,32 32,30.65 32,29 L32,3 C32,1.35 30.65,0 29,0 Z" id="Path"></path>   
</svg>

我们只需要将其中 <path> 部分代码放到图标组件的 <template> 中,比如 facebook.svg 的放到对应的 Fackbook.vue 组件:

<!-- Facebook.vue -->
<template>
    <path d="M29,0 L3,0 C1.35,0 0,1.35 0,3 L0,29 C0,30.65 1.35,32 3,32 L16,32 L16,18 L12,18 L12,14 L16,14 L16,12 C16,8.69375 18.69375,6 22,6 L26,6 L26,10 L22,10 C20.9,10 20,10.9 20,12 L20,14 L26,14 L25,18 L20,18 L20,32 L29,32 C30.65,32 32,30.65 32,29 L32,3 C32,1.35 30.65,0 29,0 Z" id="Path"></path>      
</template>

<script>
    export default {
        name:'Facebook'
    }
</script>

对于 GooglePlus.vueTwitter.vue 组件类似。

为了更好的演示官网提供的示例,将在 components 目录中新创建一个 .vue 文件,将引用我们创建的 FacebookTwitterGooglePlus 组件。该文件名暂时取名为 VueOfficialSvgIcons.vue ,接下来我们就可以这样使用这几个SVG图标:

<!-- VueOfficialSvgIcons.vue -->
<template>
    <div class="icons">
        <IconBox icon-name="facebook"><Facebook /></IconBox>
        <IconBox icon-name="twitter"><Twitter /></IconBox>
        <IconBox icon-name="google plus"><GooglePlus /></IconBox>
    </div>
</template>

<script>
    import IconBox from './icons/IconBox'
    import Facebook from './icons/Facebook'
    import Twitter from './icons/Twitter'
    import GooglePlus from './icons/GooglePlus'

    export default {
        name: 'VueOfficialSvgIcons',
        components: {
            IconBox,
            Facebook,
            Twitter,
            GooglePlus
        }
    }
</script>

现在看到的效果,都是默认的尺寸 32px x 32px

如何在Vue项目中使用SVG Icon

如果我们需要多种尺寸的图标,可以像下面这样做:

<!-- VueOfficialSvgIcons.vue -->
<IconBox 
    width="16"
    height="16"
    icon-name="facebook"><Facebook /></IconBox>

<IconBox icon-name="twitter"><Twitter /></IconBox>

<IconBox 
    width="48"
    height="48"
    icon-name="google plus"><GooglePlus /></IconBox>

得到的效果如下:

如何在Vue项目中使用SVG Icon

如果你需要不同的图标颜色,可以通过 iconColor 传一个图标的颜色:

<!-- VueOfficialSvgIcons.vue -->
<IconBox 
    icon-color="#f36"
    icon-name="facebook"><Facebook /></IconBox>

<IconBox 
    icon-color="#f0987a"
    icon-name="twitter"><Twitter /></IconBox>

<IconBox icon-name="google plus"><GooglePlus /></IconBox>

效果如果如下:

如何在Vue项目中使用SVG Icon

这是Vue项目中使用SVG图标最基本的方式。通过上面的示例我们可以看出来,如果你还需要更多的控制SVG图标,可以在 IconBox 基本组件中的 props 设置更多的属性。在使用的时候按需传入即可。

SVG Sprite的使用

上面这种方式,每个Icon都需要一个独立的组件。如果你的Web应用有许多图标用在不同的地方时,这种方式较为适合。如果你只在一个页面上重复使用相同图标多次,那么使用SVG Sprite更为理想。

有关于SVG Sprites的使用可以阅读《SVG Sprite》一文。

简单地说,可以通过SVG的 <symbol> 标签把所以SVG图标合并在一起,然后使用 <use> 标签来调用 <symbol> 中指定的图标。即 <use> 中的 xlink:href 属性值与 <symbol> 标签指定的 id 相同。

在这里,我们来看看在Vue中怎么使用SVG Sprites来创建图标。基于上面的示例,我们先创建一个名为 Icon.vue 组件:

<!-- Icon.vue -->
<template>
    <svg :width="width" :height="height" :style="{color: iconColor}">
        <use xmlns:xlink="http://www.w3.org/1999/xlink" :xlink:href="iconId"></use>
    </svg>
</template>

<script>
    export default {
        name: 'Icon',
        props: {
            iconName: {
                type: String,
                default: 'box'
            },
            width: {
                type: [Number, String],
                default: 32
            },
            height: {
                type: [Number, String],
                default: 32
            },
            iconColor: {
                type: String,
                default: 'currentColor'
            }
        },
        computed: {
            iconId() {
                return `#icon-${this.iconName}`
            }
        }
    }
</script>

现在 Icon 组件是功能性的了,我们需要在 src/mail.js 中注册到 Vue 实例中:

<!-- src/main.js -->
import iconComponent from './components/svgSprites/Icon'
Vue.component('icon', iconComponent)

为了区分前面的示例,这里为SVG Sprites单独创建一个独立的组件,比如 SvgSpritesIcon.vue 组件,然后再这个组件中调用:

<icon icon-name="facebook"></icon>
<icon icon-name="twitter"></icon>
<icon icon-name="google"></icon>

但在页面中并不会看到有任何的Icon。这主要是因为我们还没有创建SVG Sprites。暂时我们人肉创建一个SVG Sprites,比如在 App.vue 文件中创建一个SVG Sprites:

<!-- App.vue -->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
    <symbol viewBox="0 0 32 32" id="icon-facebook" fill="currentColor">
        <path d="M29,0 L3,0 C1.35,0 0,1.35 0,3 L0,29 C0,30.65 1.35,32 3,32 L16,32 L16,18 L12,18 L12,14 L16,14 L16,12 C16,8.69375 18.69375,6 22,6 L26,6 L26,10 L22,10 C20.9,10 20,10.9 20,12 L20,14 L26,14 L25,18 L20,18 L20,32 L29,32 C30.65,32 32,30.65 32,29 L32,3 C32,1.35 30.65,0 29,0 Z"></path>      
    </symbol>
    <symbol viewBox="0 0 32 32" id="icon-twitter" fill="currentColor">
        <path d="M28.5714286,0 L3.42857143,0 C1.53571429,0 0,1.53571429 0,3.42857143 L0,28.5714286 C0,30.4642857 1.53571429,32 3.42857143,32 L28.5714286,32 C30.4642857,32 32,30.4642857 32,28.5714286 L32,3.42857143 C32,1.53571429 30.4642857,0 28.5714286,0 Z M25.0785714,11.3428571 C25.0928571,11.5428571 25.0928571,11.75 25.0928571,11.95 C25.0928571,18.1428571 20.3785714,25.2785714 11.7642857,25.2785714 C9.10714286,25.2785714 6.64285714,24.5071429 4.57142857,23.1785714 C4.95,23.2214286 5.31428571,23.2357143 5.7,23.2357143 C7.89285714,23.2357143 9.90714286,22.4928571 11.5142857,21.2357143 C9.45714286,21.1928571 7.72857143,19.8428571 7.13571429,17.9857143 C7.85714286,18.0928571 8.50714286,18.0928571 9.25,17.9 C7.10714286,17.4642857 5.5,15.5785714 5.5,13.3 L5.5,13.2428571 C6.12142857,13.5928571 6.85,13.8071429 7.61428571,13.8357143 C6.30917726,12.9675977 5.52600528,11.5031734 5.52857143,9.93571429 C5.52857143,9.06428571 5.75714286,8.26428571 6.16428571,7.57142857 C8.47142857,10.4142857 11.9357143,12.2714286 15.8214286,12.4714286 C15.1571429,9.29285714 17.5357143,6.71428571 20.3928571,6.71428571 C21.7428571,6.71428571 22.9571429,7.27857143 23.8142857,8.19285714 C24.8714286,7.99285714 25.8857143,7.6 26.7857143,7.06428571 C26.4357143,8.15 25.7,9.06428571 24.7285714,9.64285714 C25.6714286,9.54285714 26.5857143,9.27857143 27.4285714,8.91428571 C26.7928571,9.85 25.9928571,10.6785714 25.0785714,11.3428571 Z"></path>        
    </symbol>
    <symbol viewBox="0 0 32 32" id="icon-google" fill="currentColor">
        <path d="M28.5714286,0 L3.42857143,0 C1.53571429,0 0,1.53571429 0,3.42857143 L0,28.5714286 C0,30.4642857 1.53571429,32 3.42857143,32 L28.5714286,32 C30.4642857,32 32,30.4642857 32,28.5714286 L32,3.42857143 C32,1.53571429 30.4642857,0 28.5714286,0 Z M11.7142857,23.1428571 C7.76428571,23.1428571 4.57142857,19.95 4.57142857,16 C4.57142857,12.05 7.76428571,8.85714286 11.7142857,8.85714286 C13.6428571,8.85714286 15.25,9.55714286 16.5,10.7285714 L14.5642857,12.5928571 C14.0357143,12.0857143 13.1142857,11.4928571 11.7214286,11.4928571 C9.28571429,11.4928571 7.3,13.5071429 7.3,16.0071429 C7.3,18.5 9.28571429,20.5214286 11.7214286,20.5214286 C14.55,20.5214286 15.6071429,18.4857143 15.7785714,17.4428571 L11.7142857,17.4428571 L11.7142857,14.9857143 L18.4571429,14.9857143 C18.5285714,15.3428571 18.5714286,15.7071429 18.5714286,16.1714286 C18.5714286,20.25 15.8357143,23.1428571 11.7142857,23.1428571 Z M27.4285714,17.3 L25.3571429,17.3 L25.3571429,19.3714286 L23.2714286,19.3714286 L23.2714286,17.3 L21.2,17.3 L21.2,15.2142857 L23.2714286,15.2142857 L23.2714286,13.1428571 L25.3571429,13.1428571 L25.3571429,15.2142857 L27.4285714,15.2142857 L27.4285714,17.3 Z"></path> 
    </symbol>
</svg>

此时,你刷新你的页面,可以看到图标,如下图所示:

如何在Vue项目中使用SVG Icon

和前面的示例一样,我们可以通过 props 中的 widthheighticonColor 来设置图标的大小和颜色,比如:

<icon icon-name="facebook"></icon>
<icon icon-name="twitter" width="48" height="48"></icon>
<icon icon-name="google" width="64" height="64" icon-color="green"></icon>

此时的效果如下:

如何在Vue项目中使用SVG Icon

上面的示例中,虽然达到我们想要的效果。但SVG Sprite是我们人肉生成的。其实,我们可以借助相关的 工具 链,自动生成SVG Sprite。比如:

这些工具会在编译时打包 SVG,但是在运行时编辑它们会有一些麻烦,因为 <use> 标签在处理一些复杂的事情时存在浏览器兼容问题。同时它们会给你两个嵌套的 viewBox 属性,这是两套坐标系。所以实现上稍微复杂了一些。

接下来我们以 svg-sprite-loader 为例,看看怎么自动生成SVG Sprite。我先从网上下载几个SVG的图标放在项目 src/assets/icons/ 下:

如何在Vue项目中使用SVG Icon

注意,我们的环境是Vue Cli3下。

先进行安装:

npm i svg-sprite-loader -D

现在我们需要做一些配置。Vue Cli内部是利用 webpack-chain 插件来修改Webpack配置的。所以我们需要在项目根目录下创建一个 Vue.config.js 文件,在该文件中利用 webpack-chain 来修改相关的Webpack配置。比如:

// Vue.config.js
const path = require('path')

function resolve(dir) {
    return path.join(__dirname, '.', dir)
}

module.exports = {
    chainWebpack: config => {
        config.module.rules.delete('svg')

        config.module
            .rule('svg-sprite-loader')
            .test(/\.svg$/)
            .include
            .add(resolve('src/assets/icons')) // svg图标的路径
            .end()
            .use('svg-sprite-loader')
            .loader('svg-sprite-loader')
            .options({
                symbolId: 'icon-[name]' // 设置svg中symbol中id的值
            })
    }
}

前面也提到过了,使用SVG Sprite,需要有一个模板,比如 /src/components/svgSprites/Icon.vue 组件:

<!-- /src/components/svgSprites/Icon.vue -->
<template>
    <svg :width="width" :height="height" :style="{color: iconColor}">
        <use xmlns:xlink="http://www.w3.org/1999/xlink" :xlink:href="iconId"></use>
    </svg>
</template>

<script>
    export default {
        name: 'Icon',
        props: {
            iconName: {
                type: String,
                default: 'box'
            },
            width: {
                type: [Number, String],
                default: 32
            },
            height: {
                type: [Number, String],
                default: 32
            },
            iconColor: {
                type: String,
                default: 'currentColor'
            }
        },
        computed: {
            iconId() {
                return `#icon-${this.iconName}`
            }
        }
    }
</script>

虽然配置和模板都有了,但要使用还是需要人肉的引用 .svg 文件。所以我们借助Webpack的一些功能,来自动帮我们引入。接下来在 /src 目录下创建一个 utils/svg-icons 目录,并在该目录下创建一个 index.js

// src/utils/svg-icons/index.js
import Vue from 'vue'

import iconSpriteLoadComponent from '../../components/svgSprites/Icon.vue'

Vue.component('icon',iconSpriteLoadComponent)

const requireAll = requireContext => requireContext.keys().map(requireContext)
const req = require.context('../../assets/icons', false, /\.svg$/)

requireAll(req)

上面这段代码主要是用于注册 Icon 组件和批量引入 .svg 文件。有了这些之后,我们就可以像下面这样使用:

<icon icon-name="close"></icon>
<icon icon-name="love"></icon>
<icon icon-name="star" width="48" height="48"></icon>

将看到的效果如下:

如何在Vue项目中使用SVG Icon

通过 Icon.vue 组件中的 props 定义的属性,将相关的值传入进去。同样可以设置大小,但这里有一个小细节,如果你想像前面的示例通过 iconColor 来给图标传递相应的颜色时会失效,比如:

<icon icon-name="location" width="24" height="24" icon-color="red"></icon>
<icon icon-name="collection" width="48" height="48" icon-color="lime"></icon>

颜色并没有重置过来:

如何在Vue项目中使用SVG Icon

那是因为,我们的 .svg 文件中 path 标签中的 fill 有一个默认值:

如何在Vue项目中使用SVG Icon

如果要让 iconColor 值生效,我们需要将 .svg 中的 fill (和 stroke )属性的值设置为 currentColor 。修改之后,你就能看到图标有相应的颜色了:

如何在Vue项目中使用SVG Icon

这里是通过人肉去修改每个 .svg 文件中 fillstroke 属性,即 将其值修改为 currentColor 。不知道有没有相应的工具,能在合并成SVG Sprite时,自动将 fillstroke 的值更换为 currentColor 。找了一圈,没找到。如果您在这方面有相应的经验,欢迎分享出您的方案。

上面是在Vue Cli3环境中的使用,如果你是自己的构建系统,那么可以借助Webpack相关配置,达到相应的效果。只需要修改 /build/webpack.base.conf.js 文件:

{
    test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
    exclude: [resolve('src/assets/icons')], // 新增加
    loader: 'url-loader',
    options: [
        limit: 10000,
        name: utils.assetsPath('img/[name].[hash:7].[ext]')
    ]
}

// 另外增加
{
    test: /\.svg$/,
    loader: 'svg-sprite-loader',
    include: [resolve('src/assets/iocns')],
    options: [
        symbolId: 'icon-[name]'
    ]
}

其他地方可以不修改。

注册事项

虽然SVG图标在Web中的运用越来越广泛,但是在使用和设计的时候还是需要注意一些细节,比如 .svg 文件的优化。大家都知道,用文本编辑器打开一个 .svg 文件,将看到一大坨的代码,如果你不知道什么可删除,什么不可删除,那么可以借助SVGOMG来优化:

如何在Vue项目中使用SVG Icon

代码上的变化如下:

如何在Vue项目中使用SVG Icon

另外有一点也需要特别注意,那就是SVG 图示的绘制。虽然在很多平台上能直接下载到自己需要的SVG图标,但有时候为了更适合自己的项目,设计师会为自己提供一些更具个性化的SVG图标,这个时候,需要一套较为标准的绘制规则和流程。有关于这方面可以参考 iconfont上的图标绘制规则和制作流程

写在最后

有关于在Vue项目中使用SVG的方案和相关的组件库在Github上非常的多。大家可以选择适合自己的组件,如果你喜欢 Font Awesome 图标的话,那么@E0 大大的 Vue-Awesome 就是一个不错的选择。

最后再说一点,这篇文章主要是亲测了在Vue项目中怎么灵活或者更好的使用SVG图标。文章开头跟着 Vue官网 提供的方式,做了一些尝试,感觉较为简单,特别适合那种,项目中运用图标不多的场景,可以为每个图标创建一个独立的组件,不需要全局注册,也可以在任何需要的地方使用。如果图标较多时,管理起来有点蛋疼而以。文章第二部分,介绍如何自动化生成SVG Sprite,并且在相应的脚手架中运用。

可能文章中有不对或者不好的地方,如果你有这方面的经验,欢迎拍正和分享。 文章中示例代码可以在Github中获取到


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Build Your Own Web Site the Right Way Using HTML & CSS

Build Your Own Web Site the Right Way Using HTML & CSS

Ian Lloyd / SitePoint / 2006-05-02 / USD 29.95

Build Your Own Website The Right Way Using HTML & CSS teaches web development from scratch, without assuming any previous knowledge of HTML, CSS or web development techniques. This book introduces you......一起来看看 《Build Your Own Web Site the Right Way Using HTML & CSS》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

MD5 加密
MD5 加密

MD5 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换