SVG 使用教程:如何在 Vue 中使用 SVG icon 图标系统

A kitten
战场小包
前端实习生
最近更新 2022年04月10日

如何在 Vue 中使用 SVG icon 图标系统

本教程教大家如何在 Vue 中引入 SVG icon 图标系统,然后教大家如何一步步搭建一套 SVG 图标系统,下图为跟随本教程最终的搭建效果。

SVG 图标搭建效果 本教程所涉及到的案例源码可在 github 下载:https://github.com/HiJiangChuan/using-svg-and-vue-complete-guide

目前 网站/app 内展示图标的主流方案就是 svg-icon 方法。我先带大家来回顾一下 icon 的演变史。然后详细讲解如何在 vue 中使用 svg-icon 方法。最后跟着我的教程一起搭一套 SVG 图表系统。

img 年代

最早网站中使用的所有的图标都是通过 img 进行实现,但随着项目的复杂,需要的图标越来越多,网站中会出现越来越多的图片请求,这严重影响了网站的加载性能。

后来出现了 image sprite 雪碧图技术,即把多张图片合成一张图片,然后利用 cssbackground-position 定位配合 overflow:hidden 来显示不同的图标。

雪碧图出现大大减少了图片的请求量,但增加了开发的复杂度,例如每次使用图标需要测量位置,新增图标需要修改雪碧图等。

iconfont 年代

网站中使用的某些图标相对比较简单,因此大佬们寻求将简单的图标设计成文字格式,即图标本质是文字,我们只需要按照引入文字的方式引入图标即可。

iconfont 字体图标也有三种使用方法:

  1. 基于 unicode 模式: unicode 模式大家肯定非常熟悉,大致是下面这样的流程:
1. @font-face 引入自定义字体
2. 定义使用iconfont的样式
3. 使用 i 图标,然后传入对应的图标编码
<i class="iconfont">&#xe604;</i>

这种实现方式最大的缺点是编码部分 &#xe604; ,使用编码的方式非常不直观,语义也比较差。

  1. 基于 font-class: 图标编码格式使用起来非常不直观,因此大佬们将这些编码提前封装好,整合在 css 文件中,使用模式就变成了下述情况。
1. 引入对应 css 文件 font.css
2. 通过类名使用: <i class="iconfont icon-xxx"></i>
  1. 当前主流模式: svg-icon 模式

上面两种使用起来都难免有自己的缺点,svg 格式出现了,svg 不仅兼容了 font 方式的优点,还具备独特的优势:

  • svg 是矢量图,缩放不会发生失真
  • 支持多色图标(上面两种方式不支持)
  • 可以很精细的控制 svg 图标的每一部分
  • ...

svg 方式来实现 icon 图标非常便捷,逐渐成为图标的主流方案。那 vue 项目中如何便捷舒适的使用 svg-icon 呐?别急,本文给你慢慢道来。

另外,这个世界已经悄然发生变化,现在根本无需写任何前端代码,直接使用卡拉云 —— 新一代低代码开发工具帮你搭建后台工具,卡拉云可一键接入常见数据库及 API ,无需懂前端,内置完善的各类前端组件,无需调试,拖拽即用。原来三天的开发工作量,使用卡拉云后可缩减至 1 小时,欢迎免费试用卡拉云

调试 Vue 太麻烦?

试用卡拉云,拖拽组件连接 API 和数据库直接生成后台系统,将两个月的工期降低至两天

第一步: 安装 CLI 及创建项目

首先我们需要通过 npm 或者 yarn 安装 vue-cli 工具,用于创建我们的 vue 项目。然后检查是否安装成功。

npm install -g @vue/cli
vue --version
C:\Users\xxx>vue --version
@vue/cli 5.0.3

接着我们使用 vue 命令来创建 vue 项目。

vue 开发中,手动配置无疑是非常复杂的,vue 官方提供了 Vue-CLI 可以让你非常友好快捷的配置你所需要的项目模板。Vue-CLI 提供了命令行交互方式,可自由的选择所需要项目配置配置。

首先进入需要创建 vue 项目的目录,运行下面的创建命令:

vue create kalacloud-svg-vue

上面的命令是创建 vue 项目的起始命令,执行完毕后,会进入第一个交互页面:

? Please pick a preset: (Use arrow keys)
  Default ([Vue 3] babel, eslint)
> Default ([Vue 2] babel, eslint)
  Manually select features

等待项目安装完毕后,使用 cd 命令进入项目目录,然后启动当前应用程序:

cd kalacloud-svg-vue
npm run serve

项目成功运行后,你可以在浏览器中访问 http://localhost:8080/ ,你将会看到 Vue 初始项目的页面。

vue-demo

第二步:svg-sprite-loader 使用

Vue 项目中安装 svg-sprite-loader 依赖。安装成功后,你可以在 package.json 看到 svg-sprite-loader 及其版本信息。

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

svg-sprite-package-json

在项目的 src 目录下新建 src/icons/svg 目录,存放项目所使用的所有图标 svg 文件。

修改配置文件 vue.config.js ,使得 src/icons 目录下的 .svg 使用 svg-sprite-loader 来解析。

vue-config.js 中添加下面配置:

const path = require("path");

function resolve(dir) {
  return path.join(__dirname, "./", dir);
}

module.exports = {
  chainWebpack(config) {
    config.module.rule("svg").exclude.add(resolve("src/icons")).end();
    config.module
      .rule("icons")
      .test(/\.svg$/)
      .include.add(resolve("src/icons"))
      .end()
      .use("svg-sprite-loader")
      .loader("svg-sprite-loader")
      .options({
        symbolId: "icon-[name]",
      })
      .end();
  },
};

删除 Vue 初始化项目创建的多余代码,在项目中创建组件 components/SvgIcon.vue

<template>
  <svg class="svg-icon" aria-hidden="true">
    <use :xlink:href="iconName" />
  </svg>
</template>
<style>
  .svg-icon {
    width: 1.5em;
    height: 1.5em;
  }
</style>
<script>
  export default {
    props: {
      iconClass: {
        type: String,
        required: true,
      },
    },
    computed: {
      iconName() {
        return `#icon-${this.iconClass}`;
      },
    },
  };
</script>

src/icons 目录下创建 icons 目录的入口文件 index.js ,负责所有图标文件的加载。

import Vue from "vue";
import SvgIcon from "@/components/SvgIcon";
Vue.component("svg-icon", SvgIcon);

/**
 * require.context 的参数说明
 * './svg' 代表要查找的文件路径
 * false 代表是否查找子目录
 * /\.svg$/ 代表要匹配文件的正则
 *
 */
const svg = require.context("./svg", false, /\.svg$/);
const requireAll = (requireContext) =>
  requireContext.keys().map(requireContext);
requireAll(svg);

如果你的项目图标文件比较多,可以对 icons 目录做更详细的划分,例如你需要在首页和详情页使用 icon,你可以设置两个文件夹 mainSvgdetailSvg,然后修改一下上述 index.js

main.js 入口文件中 全局引入 icons

// main.js
import "./icons";

我们去 iconfont 图标网站下载几个 svg 图标,用来测试上面的配置是否成功。

将下载的 svg 图标放置到 src/icons/svg 目录下,这里作者下载了星星图标和收藏图标。

接下来修改 App.vue 部分代码,

<template>
  <div id="app">
    <div class="svg-content">
      <h1>如何在 Vue 中使用 SVG icon 图标系统</h1>
      <h2>
        卡拉云——低代码开发工具,1 秒搭建上传后台
     
        <svg-icon icon-class="unstar"></svg-icon>
        <svg-icon icon-class="stared"></svg-icon>
      </h2>   // 引入下载的图标——直接通过图标名引入即可
    </div>
  </div>
</template>

<script>
export default {
    name: 'App',
};
</script>

<style>
#app {
    font-family: Avenir, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-align: center;
    color: #2c3e50;
    display: flex;
    justify-content: center;
    flex-direction: column;
}
.svg-content {
    display: flex;
    justify-content: center;
    flex-direction: column;
    align-items: center;
    margin-right: 20px;
}

</style>

svg-vue-test

到这里,我们已经成功在 vue 项目中使用 svg 图标。

第三步:SvgIcon 组件应用

上面我们创建了 SvgIcon 组件,下面我们利用这个组件来实现几个功能。

收藏与取消收藏

SvgIcon 组件接收父组件传入的 iconClass 属性,来标识当前使用的 svg 图标,因此我们可以通过修改此属性来实现图标的切换。

// stared 值来代表收藏与否,值为 true 意为收藏了,因此返回收藏的图标名 stared 即可
<template>
  <div id="app">
    <div class="svg-content">
      <h1>如何在 Vue 中使用 SVG icon 图标系统</h1>
      <h2>
        卡拉云——低代码开发工具,1 秒搭建上传后台
        <svg-icon :icon-class="stared ? 'stared': 'unstar'" @click.native="toggle"></svg-icon>
      </h2>
    </div>
  </div>
</template>
<script>
export default {
    name: 'App',
    data() {
        return {
            stared: false,
        };
    },
    methods: {
        toggle() {
            this.stared = !this.stared;
        },
    },
};
</script>

svg-icon 是组件,无法检测到 click 事件,因此我们可以添加 .native 事件修饰符来实现对 click 事件的监听。

我们实现收藏与取消收藏的功能后,我们可以在这个基础上实现些比较复杂的业务处理逻辑,比如当用户收藏后提醒用户,用户取消收藏时询问用户等。

利用 element-ui 提供的组件实现上述功能。

1: 安装 element-ui

npm i element-ui -S

2:引入 element-uimain.js 中写入以下内容:

import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";

Vue.use(ElementUI);

3:实现功能

methods: {
  toggle() {
    if (this.stared) {
        // 询问是否要取消收藏
        this.cancelStar();
    } else {
        // 收藏按钮
        this.stared = !this.stared;
        this.$message({
          message: '成功收藏卡拉云,下面开始你的使用吧',
          type: 'success',
        });
    }
  },
  cancelStar() {
    // element-ui 提供的 messagebox 组件
    this.$confirm(
        '卡拉云——低代码开发工具,1 秒搭建上传后台',
        '取消卡拉云收藏',
        {
            distinguishCancelAndClose: true,
            confirmButtonText: '确认',
            cancelButtonText: '放弃修改',
        }
    )
        .then(() => {
            this.stared = !this.stared;
            this.$message({
                type: 'warning',
                message: '取消收藏成功',
            });
        })
        .catch(action => {
            this.$message({
                type: 'info',
                message:
                    action === 'cancel'
                        ? '未取消卡拉云收藏'
                        : '停留在当前页面',
            });
        });
    },
},

svg-star

在 Vue 中创建动态图标

在项目中使用图标不止可以让网站内容更丰富,图文并茂;另一面图标也会起到很好的提示作用。例如(√)暗示成功或者完成,(×)暗示失败等。

svg-status

例如上图所示的三种图标:

  • 没有任何提示的普通文字信息
  • 带有成功(√)提示的文字信息
  • 带有失败(×)提示的文字信息

我们在原有 SvgIcon 组件的基础上做扩展,新建一个 components/SvgText 组件,当前组件可以展示文字和图标信息。

// SvgText.vue 的源码如下:
<template>
  <div class="msg-text-container">
    <div class="text-wrap">
      {{text}}
      <svg-icon :iconClass="icon" class="icon-pos" v-if="isNeedIcon"></svg-icon>
    </div>
  </div>
</template>

<script>
export default {
    props: {
        text: {
            type: String,
            require: true,
        },
        icon: {
            type: String,
        },
        isNeedIcon: {
            type: Boolean,
            default: true,
        },
    },
};
</script>

<style>
.msg-text-container {
    margin: 10px 0;
}
.text-wrap {
    display: inline-block;
    padding: 10px 40px;
    border-radius: 40px;
    background-color: rgb(135, 176, 196);
    color: #fff;
    font-size: 24px;
    position: relative;
}
.icon-pos {
    position: absolute;
    right: -16px;
    top: 3px;
    background-color: #fff;
    z-index: 100;
    border-radius: 50%;
}
</style>

SvgText 组件共可以接收三个参数:

  • text: 标签需要展示的文字信息
  • icon: 标签使用的图标名称
  • isNeedIcon: 是否需要标签,默认为 true

SvgText 是一个 Vue 组件,因此在项目中我们可以使用 v-if v-for 等渲染使用它。

App.vue 中修改为以下内容:

<template>
  <div id="app">
    <div class="svg-content">
      <h1>如何在 Vue 中使用 SVG icon 图标系统</h1>
      <h2>
        卡拉云——低代码开发工具,1 秒搭建上传后台
        <svg-icon :icon-class="stared ? 'stared': 'unstar'" @click.native="toggle"></svg-icon>
      </h2>
    </div>
    // 支持 v-for
    <div class="svg-list">
      <svg-text v-for="(item,index) in kalacloud" :text="item.text" :icon="item.type" :key="index"></svg-text>
    </div>
  </div>
</template>

<script>
import SvgText from './components/SvgText.vue';
export default {
    name: 'App',
    components: {
        SvgText,
    },
    data() {
        return {
            stared: false,
            kalacloud: [
                { text: '极速搭建业务系统', type: 'success' },
                { text: '数十倍提升开发效率', type: 'success' },
                { text: '灵活的控件系统', type: 'success' },
                { text: '不使用卡拉云', type: 'error' },
            ],
        };
    },
    methods: {
      // method 方法未作改变,不重复罗列
        toggle() {
        },
        cancelStar() {
        },
    },
};
</script>

<style>
.svg-list {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
}
</style>

svg-text-for

通过上图可以发现,我们成功把 kalacloud 数组的数据渲染成带图标的标签信息。

我们还可以继续做扩展,例如支持标签的删除和插入等,这部分本文就不做扩展了,有想法的小伙伴可以继续实现。

SVG icon 图标系统总结

文章系统的介绍了 svg-icon 模式在 vue 项目中的使用。如果你已经系统的实现了一遍,你会发现在 vue 中使用 svg 图标主要有以下要点:

  • 配置 svg-sprite-loader 插件,vue 项目可解析对应的 svg 图标文件
  • 创建 SvgIcon 组件,何时需要图标直接引入组件即可。(更复杂的使用同样基于 SvgIcon 组件进行扩展)
  • 图标存储在 src/icons/ 目录下,项目中直接使用图标名即可。

如果你不想处理前端问题,想轻松搭建后台工具,推荐使用卡拉云,开发者完全不用处理任何前端问题,只需简单拖拽,即可快速生成所需组件,可一键接入包括 MySQL 在内的常见数据库及 API,根据引导简单几步打通前后端,数周的开发时间,缩短至 1 小时。

卡拉云天气预报数据看板

上面为使用卡拉云 10 分钟内搭建的「天气预报数据看板」,简单拖拽,几行代码即可快速完成,搭建即发布,可一键分享给其他同学一起使用。立即注册使用卡拉云。

扩展阅读: