vue引入iconfont图标库的优雅实战记录

目录
  • 前言
  • 生成SVG
    • svg sprites简介
    • 获取项目图标
  • 项目设置
    • 图标引用
    • 组件引用
  • 多主题支持
    • 配置多主题样式
    • Icon改造
    • 页面校验
  • 尾言

前言

本文撰写的初衷是为了向组内成员推行使用svg sprites的方式管理项目的图标,由于实际工作中很多项目仍然采用font class的方式,这样不自觉带来一个痛点.

当项目一期开发完毕后,过段时间进入到项目二期。新增的开发需求不可避免的会增加新的图标,而font class需要全量打包图标的字体文件.

哪怕新需求只添加了一个图标,而前端同学却要将旧图标和新图标融合后重新打包生成一次字体文件,这样的结果让人无法接受.
svg sprites能完美的解决这一问题.整体思路是先将项目中每一个图标都生成一个svg文件与之对应,那么有多少个svg文件就相当于对应了多少个图标.

以后如果想新增一个图标,那么只需要添加一个新svg文件即可.那些已经存在的图标和svg文件则不需要再参与进来.
本文接下来将以vue3为基础框架,iconfont为图标库,一步步实践图标引入,使用以及管理的整个流程.另外在文章的后半部分,还会介绍一下多主题变色模式下svg图标的相应处理.

生成SVG

svg sprites简介

svg sprites这项技术很早就出来了,具体详情可以点击查看张鑫旭在2014年写的文章未来必热:SVG Sprites技术介绍.

我们这里做一下简单介绍就进入实践阶段.svg sprites主要基于两个标签元素:<symbol>和<use>.

<symbol>对元素进行分组,它不会显示在界面上,相当于定义一个模板.<use>元素用于引用并渲染图标.

例如存在以下某个svg图标(代码如下),它是一个爱心的形状.

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 24 24">
        <path fill="#E86C60" d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
</svg>

现在使用symbol标签将上面的path内容包裹一层,代码如下:

<svg>
    <symbol viewBox="0 0 24 24" id="heart">
        <path fill="#E86C60" d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
    </symbol>
</svg>

接下来把symbol包裹后的代码放入页面中(代码如下),再添加一个display: none隐藏起来.这就相当于在页面上注册了一个id名为heart的图标.

此时页面的其他部分就可以引用这个图标,引用方式是在svg标签里面放入一个use标签,use标签的xlink:href填上要引用的图标id,界面就会渲染出爱心的形状.

<body>
    <svg style="display: none;">
        <symbol viewBox="0 0 24 24" id="heart">
            <path fill="#E86C60" d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
        </symbol>
    </svg>

    <svg>
        <use xlink:href="#heart" rel="external nofollow"   /> <!-- 使用图标 -->
    </svg>
</body>

获取项目图标

前端同学拿到设计图之后,通常会整体浏览一遍整个项目需要用到的所有图标.

iconfont是阿里巴巴体验团队倾力打造的矢量图标库,里边包含海量的图标可供前端工程师选择和使用.

浏览器点击打开 iconfont官网 ,选择好自己的项目中要用到的图标,鼠标移动到图标上点击添加入库.

图标收集完后点击头部右侧导航栏的购物车,出现弹出框,点击添加至项目.所有图标确定添加到项目后,页面会自动跳转到导航栏资源管理--我的项目下的页面(如下图).

我们的目标是为了生成图标对应的svg文件,这里要做一下设置.打开上图中的项目设置选项,弹框打开后如下图.

弹框字体格式的那一栏,只保留SVG勾选项,其他都取消,设置好后点击保存按钮.

页面此时会刷新一遍,然后点击页面上的下载至本地的按钮,将所有图标的svg文件下载下来并解压,解压后的文件结构如下图.

观察上图中的文件结构,我们发现所有svg图标的代码全部都写在iconfont.svg这一个文件,这并不符合预期.我们希望的结果是一个图标对应一个svg文件,而不是像现在一样全部揉进了一个文件内.

虽然iconfont目前没有提供文件分离的机制,但是我们可以借助其他平台帮我们将融合的svg文件分离成单个文件.

iconmoon 网站便具备这个功能,它也是一家和iconfont类似的图标库网站.

浏览器点击打开iconmoon官网 ,选择顶部导航栏右侧的IcoMoon App进入图标选择页面,点击页面头部导航栏左侧的Imports Icons,将从iconfont下载的iconfont.svg文件导入,结果如下图.

在iconfont那一栏可以看到我们导进去的图标展现到了页面上,接下来使用鼠标单击导进去的图标将其标记为选中,再点击页面左下角的Generate SVG & More按钮(如下图).

按钮点击后页面跳转,此时依旧点击左下角的Download按钮(如下图)下载图标.

下载完成后解压目录,解压后的目录下出现了SVG文件夹,打开该文件夹会发现所有图标都被分离成了单个文件(如下图).

项目设置

svg文件顺利获取到了,现在在vue3项目目录结构src -> assets文件夹下新建文件夹fonts和子文件夹fonts/svg,将上面生成的所有svg单文件扔到fonts/svg下面.
文件的设置完成,现在开始项目的配置,让vue3能顺利的管理和使用图标.

  • 第一步在项目根目录下打开命令行运行npm i svg-sprite-loader -D.我们之所以要安装依赖svg-sprite-loader,因为它能将svg文件的代码自动塞到一个个symbol标签中.
  • 第二步项目根目录下新建文件vue.config.js,熟悉vue的同学应该知道vue.config.js用来配置构建环境.

vue.config.js详细配置参数可点击查询 vue-cli官网 ,我们这里只需要知道如何配置svg-sprite-loader就可以.

众所周知,vue-cli的构建环境基于webpack,我们通过在vue.config.js文件中添加各类配置参数,vue-cli最终会将这些参数合并到webpack的配置里.

如此一来我们通过vue.config.js就能达到配置开发环境的目的,而不用直接去操作webpack的配置文件.

当前已经安装了依赖svg-sprite-loader,现在要把这个loader载入到webpack的配置中,通过在vue.config.js填写下面代码便可实现.

const resolve = require("path").resolve;

module.exports = {
   chainWebpack(config){
        //引入图标
        config.module.rule("svg").exclude.add(resolve("./src/assets/fonts/svg"));
        config.module.rule("icon").test(/\.svg$/)
        .include.add(resolve("./src/assets/fonts/svg")).end()
        .use("svg-sprite-loader")
        .loader("svg-sprite-loader")
        .options({
            symbolId:'icon-[name]'
        });
   }
}

系统学习过webpack配置的同学很容易能看出来上面代码的含义,上方代码首先将rule中设置的svg规则排除"./src/assets/fonts/svg"目录.

然后新增加一条规则icon将"./src/assets/fonts/svg"目录包含了进去,这个目录就是我们存放所有svg文件的文件夹.

代码接下来使用.use和.loader将svg-sprite-loader配置到项目环境里,并设置symbolId为icon-[name].

这里的symbolId关乎到<symbol>标签生成的id名称.如果设置symbolId为icon-[name],那么最后页面上<use>标签引用图标时就会使用icon-加上文件名.

  • 第三步在assets/fonts下面新建文件index.js(文件结构如下图),并填写下面两行代码.

这两行代码主要使用了webpack中的 require.context函数,它可以帮助我们自动引入文件模块.

require.context第一个参数代表目标文件目录,第二个参数是否应用于子文件夹,第三个参数匹配文件格式.

const load = require.context("./svg",false,/\.svg$/);
load.keys().map(load);

require.context执行完毕后返回结果load,返回值load本身就是一个引入模块的函数,另外它还包含一个keys属性,执行load.keys()返回结果如下.

 ["./arrow.svg", "./arrowon.svg", "./downarrow.svg", "./jiantou.svg", "./trash.svg", "./yiwenicon.svg"]

我们从这里可以看出load.keys()会返回fonts/svg文件夹下所有图标的相对路径,再使用loda函数去加载这些路径的文件,这样便实现了动态引入fonts/svg文件夹下的所有以.svg结尾的文件.

那么以后如果出现新增一个图标的需求,先在iconfont网站上下载单个svg文件,下载完成后直接丢到fonts/svg文件夹下就可以完成自动引入了.

最后一步在项目的入口文件main.js调用第三步新建的index.js,执行所有svg文件的自动引入(代码如下).

import { createApp } from 'vue';
import App from './App.vue'; // 根组件
import "@/assets/fonts/index"; // 执行自动引入
import router from '@/router/index'; // 路由

createApp(App).use(router).mount('#app');

通过以上四步基本完成了项目的配置,整个运行过程可以做一下简单的梳理.

入口文件main.js启动后,执行assets/fonts/index.js启动所有svg文件的自动引入.

svg-sprite-loader一旦监听到项目中引入了以.svg结尾的文件,它就会把这些svg的代码内容全部都封装到一个个<symbol>标签里面(如下图),再一起插入到页面文档中.

这将相当于svg-sprite-loader帮助我们将所有的svg图标在页面上注册了,而我们剩下的事情就是在页面上去引用图标就行了.

图标引用

我们在Home主页下填写如下代码(效果图如下).将#icon-前缀加上fonts/svg下对应的文件名拼接而成的字符串赋予xlink:href属性,那么就会渲染出该文件对应的图标.

<template>
  <div class="home">
    <p class="title">Hello world</p>
    <svg>
        <use xlink:href="#icon-trash" rel="external nofollow" /> <!-- 使用图标 -->
    </svg>
  </div>
</template>

组件引用

页面上使用svg、use标签引用图标的方式不太优雅,我们可以将它改造成组件.

在全局组件文件夹components下新建文件Icon/index.vue.该组件接受两个参数name和color(代码如下).

参数name对应要渲染的图标名称,color为需要渲染的颜色.这里需要格外注意,svg的颜色修改只能通过fill属性,color属性赋值时不奏效.

<template>
    <svg :style="{fill:color?color:''}">
        <use :xlink:href="'#icon-'+name" rel="external nofollow"  rel="external nofollow" />
    </svg>
</template>

<script>
export default {
 props:{
     name:String, //图标名称
     color:{ // 图标颜色
         type:String,
         deafult:null
     }
 }
}
</script>

现在在Home页面引用Icon组件(代码如下).

渲染的图标名称为trash,颜色为蓝色(效果图如下).

<template>
  <div class="home">
    <p class="title">Hello world</p>
    <Icon name="trash" color="blue"/><!-- 使用图标 -->
  </div>
</template>
<script>
import Icon from "@/components/Icon/index";
export default {
    components:{
        Icon
    }
}
</script>

多主题支持

通过上文讲解可知,当我们给<svg>标签赋予样式属性fill,最终图标的颜色也会发生改变,这就为我们完成多主题的开发需求提供了可能.

我们接下来搭建一个点击按钮在线切换主题的场景,让svg图标也能随着主题的变换而改变.

配置多主题样式

首选在项目文件夹src/assets下新建文件scss/variable.scss,代码内容如下.

代码定义了三个主题,分别为默认主题、主题1和主题2.每个主题都定义了自己主题下的图标颜色和背景颜色.

代码下半部分定义了3个mixin,分别用来设置fill、color和background-color属性.在每一个mixin里面,不同主题设置的颜色采用自己主题下的颜色设置.

// 默认主题
$icon-color:red;
$background-color:#fff;

// 主题1
$icon-color1:gray;
$background-color1:#eee;

// 主题2
$icon-color2:blue;
$background-color2:#999;

// 用于给svg填充颜色
@mixin fill {
    fill:$icon-color; //默认颜色用默认主题
    [data-theme = "theme1"] & { //切换到主题1时的颜色
        fill:$icon-color1;
    }
    [data-theme = "theme2"] & { //切换到主题2时的颜色
        fill:$icon-color2;
    }
}
//设置color属性
@mixin color {
    color:$icon-color; //默认颜色用默认主题
    [data-theme = "theme1"] & { //切换到主题1时的颜色
        color:$icon-color1;
    }
    [data-theme = "theme2"] & { //切换到主题2时的颜色
        color:$icon-color2;
    }
}

//设置背景颜色
@mixin backgroudColor {
    background-color:$background-color; //默认颜色用默认主题
    [data-theme = "theme1"] & { //切换到主题1时的颜色
        background-color:$background-color1;
    }
    [data-theme = "theme2"] & { //切换到主题2时的颜色
        background-color:$background-color2;
    }
}

variable.scss是一份全局多主题配置文件,该文件内不光可以配置各个主题下应该渲染的颜色,还可以配置字体大小,常用宽高等.

配置文件编写完成后,现在要将这份文件引用到项目当中.编辑器打开根目录下vue.config.js项目配置文件,新增代码如下.

const resolve = require("path").resolve;

module.exports = {
   chainWebpack(config){
        //引入图标
        config.module.rule("svg").exclude.add(resolve("./src/assets/fonts/svg"));
        config.module.rule("icon").test(/\.svg$/)
        .include.add(resolve("./src/assets/fonts/svg")).end()
        .use("svg-sprite-loader")
        .loader("svg-sprite-loader")
        .options({
            symbolId:'icon-[name]'
        });
   },
   css: {
    loaderOptions: {
        scss: {
            prependData: `@import "@/assets/scss/variable.scss";`
        },
    }
   }
}

在module.exports新增配置属性css,随后将我们在上面编写多主题配置文件的路径填入到prependData对应的值.

这里为了避免因为sass版本的不同导致文件引入失败,统一一下sass和sass-loader的版本.

"sass": "1.26.5",
"sass-loader": "8.0.2",

vue.config.js配置完成后重启应用,variable.scss已经全局注入了应用.接下来我们在页面组件内不需要使用@import导入主题配置文件,variable.scss里面定义的变量和mixin可以直接拿来使用.

Icon改造

为了让图标响应主题的变换,全局的Icon组件做如下代码修改.color属性如果有传值,那么图标就按照传入的颜色渲染.如果没有传color,那么决定图标颜色的因素变成了类名icon.

<template>
    <svg class="icon" :style="{fill:color?color:''}">
        <use :xlink:href="'#icon-'+name" rel="external nofollow"  rel="external nofollow" />
    </svg>
</template>

<script>
export default {
 props:{
     name:String,
     color:{
         type:String,
         deafult:null
     }
 }
}
</script>

<style lang="scss" scoped>
 .icon{
   @include fill;
 }
</style>

类名 icon 里面调用 fill对应的mixin,文件variable.scss对fill的定义如下面代码.

它最后返回一个属性 fill:color.默认情况下fill的颜色值为$icon-color.

当页面文档html标签上的属性data-theme值变成theme1时,fill渲染的颜色变成了主题1定义的颜色.同理切换到theme2,fill渲染的颜色变成了主题2定义的颜色.

// 用于给svg填充颜色
@mixin fill {
    fill:$icon-color; //默认颜色用默认主题
    [data-theme = "theme1"] & { //切换到主题1时的颜色
        fill:$icon-color1;
    }
    [data-theme = "theme2"] & { //切换到主题2时的颜色
        fill:$icon-color2;
    }
}

我们观察一下页面最终生成的dom结构就可以理解上面配置的目的,@mixin最终会将每个主题下的样式都生成了一份(如下图),这样一来只要<html>标签的data-theme等于哪个主题,对应主题的样式表就会生效.

页面校验

Home页面组件填写如下代码.在原来页面基础上新增了三个按钮默认主题、主题1和主题2.

点击按钮触发updateTheme函数,函数会修改<html>标签上data-theme的属性值,从而实现了主题切换的功能(效果图如下).

<template>
  <div class="home">
    <p class="title">Hello world</p>
    <Icon name="trash"/><!-- 使用图标 -->
    <button @click="updateTheme()">默认主题</button>
    <button @click="updateTheme('theme1')">主题1</button>
    <button @click="updateTheme('theme2')">主题2</button>
  </div>
</template>
<script>
import Icon from "@/components/Icon/index";
export default {
    components:{
        Icon
    },
    methods: {
        updateTheme(name){
            if(name == null){ // 采用默认主题
                document.documentElement.removeAttribute("data-theme");
            }else{
                document.documentElement.setAttribute("data-theme",name);
            }
        }
    },
}
</script>
<style scoped lang="scss">
.home{
    height: 100%;
    @include backgroudColor;
}
.title{
  @include color;
}
</style>

最终效果图:

尾言

上文介绍的多主题实现方案操作起来非常简单,但不适合用于大型复杂的项目.

试想一下,如果一个大型项目包含十几种主题,而每一类主题下的css代码十分庞大,一次性将所有主题下的样式代码全部注入到应用里是不合适的.

最佳实践应该是用户点击切换某一类主题时,就按需加载那一类主题的样式,再注入到应用中渲染,这样可以极大的提升整体性能.最佳实践方式可以参考社区内关于多主题切换的文章.

到此这篇关于vue引入iconfont图标库的文章就介绍到这了,更多相关vue引入iconfont内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

源代码

(0)

相关推荐

  • VUE在线调用阿里Iconfont图标库的方法

    前言 多年前我本是个服务端小白,随着行业内卷,硬是被熬成了前端小白...开个玩笑,只是个人比较喜欢学习技术罢了!本章将带领大家以另一个高端的方式打开阿里Iconfont图标库,过去,我们要么是自己在网上费好大劲,东拼西凑的找一些icon的图片,来美化我们的网页,然而随着技术的发展,和一些大平台的技术奉献,这里不得不说阿里还是牛逼,这里不是夸它,给它打广告,确实,人家在一些领域做的比某腾要好,可能也和领域有关吧,受我个人认知水平问题,我也只能这么认为,比如在我门JAVA服务端方向,阿里有Nacos

  • vue项目引入Iconfont图标库的教程图解

    在进行项目开发过程中,vue项目中前端所使用的UI框架是element ui,但是element的字体图标库不足以满足日常开发的需要,或者公司项目要求使用本公司ui设计的图标,都可以参考以下的步骤, 1. 在阿里图标库中选中你想要的图标库,并点击进去, 2. 注意: 我们在选择图标是后,如果是需要多个图标就将选中的图标加入购物车,但是如果我们没有在这一个图标库中找到自己需要的图标时,可以去其他的图标库中进行选择,但是要记住离开这个图标库的时候,记得将选择的图标加入自己创建的项目中, 不然去其他图

  • Vue中使用ElementUI使用第三方图标库iconfont的示例

    1.在http://www.iconfont.cn/阿里巴巴图标库添加图标到自己项目中,然后点击更多项目中的编辑项目 2.修改前缀为el-icon-xxx,xxx自定义,然后将项目下载自本地 3.将这5个文件放入到项目文件中,将iconfont.css引入到Vue项目中, 然后修改iconfont.css的.iconfont处,将其修改为下图所示 4.修改iconfont.css后,大致如下图所示 5.最后就可以采用icon相同方式引入图标,如下图方式引用即可 注意:如果修改前缀为el-icon

  • vue引入iconfont图标库的优雅实战记录

    目录 前言 生成SVG svg sprites简介 获取项目图标 项目设置 图标引用 组件引用 多主题支持 配置多主题样式 Icon改造 页面校验 尾言 前言 本文撰写的初衷是为了向组内成员推行使用svg sprites的方式管理项目的图标,由于实际工作中很多项目仍然采用font class的方式,这样不自觉带来一个痛点. 当项目一期开发完毕后,过段时间进入到项目二期.新增的开发需求不可避免的会增加新的图标,而font class需要全量打包图标的字体文件. 哪怕新需求只添加了一个图标,而前端同

  • Vue项目中如何运用vuex的实战记录

    目录 Vuex 是什么? vuex使用周期图 我的store目录 实现一个vuex的示例 总结 Vuex 是什么? TIP

  • 一次VUE项目中遇到XSS攻击的实战记录

    目录 前言 发现原因 自定义过滤规则 总结 前言 随着互联网的高速发展,信息安全问题已经成为企业最为关注的焦点之一,而前端又是引发企业安全问题的高危据点.在移动互联网时代,前端人员除了传统的 XSS.CSRF 等安全问题之外,又时常遭遇网络劫持.非法调用 Hybrid API 等新型安全问题.当然,浏览器自身也在不断在进化和发展,不断引入 CSP.Same-Site Cookies 等新技术来增强安全性,但是仍存在很多潜在的威胁,这需要前端技术人员不断进行"查漏补缺". 发现原因 一切

  • vue中使用iconfont图标的过程

    目录 vue引入iconfont图标 引入在线链接文件 vue使用iconfont多色图标 vue引入iconfont图标 引入在线链接文件 如果开发过程中需要不断更新图标,为了避免多次下载文件到本地,可以先选择使用在线链接的图标文件 前面的步骤就不赘述了,直接讲如何在vue中引入 查看项目在线链接 我 选的是 Unicode 的形式 在项目中的 assets/css 文件夹下新建 global.css 文件,复制刚才生成的 font-face 代码,如何定义iconfont 类 @font-f

  • 如何将iconfont图标引入到vant的Tabbar标签栏里边

    目录 将iconfont图标引入vant的Tabbar标签栏里 1. 首先引入tabbar 2. 以基础代码为例 vue+vant引入iconfont字体图标 将iconfont图标引入vant的Tabbar标签栏里 vant的Tabbar标签栏https://youzan.github.io/vant/ 在app开发中,这个必不可少,上一张讲了怎么引入iconfont图标,现在就将iconfont图标引入到tabbar标签栏里边,看着vant提供的图标,必将有点丑啊23333,接下来就是引入方

  • flutter项目引入iconfont阿里巴巴图标

    目录 下载图标 使用图标 注意 下载图标 这里直接去iconfont阿里巴巴矢量图标库,选好自己需要的图标,点击如下图所示[添加到库] 然后选择头像左侧的购物车图标 然后点击下载代码 引入图标 解压完打开文件夹可以看到如下文件列表,我们将.ttf文件放在项目的静态资源文件夹中[我直接放在asset文件夹下] 接着我们在项目的pubspec.yaml文件夹下引入字体文件,并设置字体族名称 fonts: - family: Iconfont fonts: - asset: asset/fonts/i

  • Vue中引入svg图标的两种方式

    Vue中引入svg图标的方式 Vue中引入svg图标的方式一 安装 yarn add svg-sprite-loader --dev svg组件 index.vue <!-- svg组件 --> <template> <svg class="svg-icon" :class="svgClass" aria-hidden="true"> <use :xlink:href="iconName&quo

  • Vue中引入第三方JS库的四种方式

    目录 一.绝对路径直接引入,全局可用 二.绝对路径直接引入,配置后,import 引入后再使用 三.webpack中配置 alias,import 引入后再使用 四.webpack 中配置 plugins,无需 import 全局可用 结论 我们以 jQuery 为例,来讲解 一.绝对路径直接引入,全局可用 主入口页面 index.html 中用 script 标签引入: <script src="./static/jquery-1.12.4.js"></script

随机推荐