Vue项目中优雅使用icon

前言

icon在咱们前端平常开发中是很经常使用的,它有不少种使用方式,时至今日,它的使用方式通过了不少种演变,本文会为你们介绍icon的一些历史演变,分析一下这几种使用方式的优劣,咱们将采用svg sprites这种方式使用icon,演示代码使用vue+vue-cli3+,看完以后,你会发现这种使用方式彻底称得上优雅二字javascript

追溯历史

Img标签引入

最先咱们使用图标时只是单纯img标签引入图片,我的感受也还好css

可是这样网页上会有不少img图标的资源请求,这是它最大的缺点html

雪碧图(css sprites)

后来咱们为了优化资源请求开始使用CSS雪碧图(css sprites)前端

CSS Sprites在国内不少人叫css精灵/css雪碧图(啥都行),是一种网页图片应用处理方式。它容许你将一个页面涉及到的全部零星图片都包含到一张大图中去,这样一来,当访问该页面时,载入的图片就不会像之前那样一幅一幅地慢慢显示出来了。加速的关键,不是下降质量,而是减小个数vue

CSS Sprites其实就是把网页中一些背景图片整合到一张图片文件中,再利用CSS的background-image background- repeat background-position的组合进行背景定位,background-position能够用数字精确的定位出背景图片的位置java

利用CSS Sprites能很好地减小网页的http请求,从而大大的提升页面的性能,这也是CSS Sprites最大的优势webpack

同时它的缺点也很明显,CSS Sprites在开发的时候比较麻烦,须要计算基准位置来进行定位,维护的时候每每改动一个图标咱们就得改整个雪碧图,一不当心就搞得整个网页的图标错位了git

font库

再到后来就出现了font库,也就是字体图标库,它出现给了咱们开发很大便利,使用起来也很是方便,字体图标为何方便,由于咱们能够直接从市面上的font字体图标库里找图标,直接使用,还能够很好的控制一些基础样式github

国内估计使用量最大也是最全的图标库我以为就是阿里矢量图标库(iconfont)了,各类图标简直不要太多,最重要的是开源免费web

拿iconfont来讲,它有三种使用方式,分别是unicode,font-class,symbol,都很是简单

固然,没有使用过的小伙伴直接百度搜索关键词iconfont使用,相信看一看就会了

接下来咱们来看下这三种方式的优缺点(官方的):

font使用方式对比

unicode引用


unicode是字体在网页端最原始的应用方式,特色是:

  • 兼容性最好,支持ie6+,及全部现代浏览器。
  • 支持按字体的方式去动态调整图标大小,颜色等等。
  • 可是由于是字体,因此不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。

注意:新版iconfont支持多色图标,这些多色图标在unicode模式下将不能使用,若是有需求建议使用symbol的引用方式

unicode使用步骤以下:

第一步:拷贝项目下面生成的font-face
@font-face {font-family: 'iconfont';
    src: url('iconfont.eot');
    src: url('iconfont.eot?#iefix') format('embedded-opentype'),
    url('iconfont.woff') format('woff'),
    url('iconfont.ttf') format('truetype'),
    url('iconfont.svg#iconfont') format('svg');
}
复制代码
第二步:定义使用iconfont的样式
.iconfont{
    font-family:"iconfont" !important;
    font-size:16px;font-style:normal;
    -webkit-font-smoothing: antialiased;
    -webkit-text-stroke-width: 0.2px;
    -moz-osx-font-smoothing: grayscale;}
复制代码
第三步:挑选相应图标并获取字体编码,应用于页面
<i class="iconfont">&#x33;</i>
复制代码

font-class引用


font-class是unicode使用方式的一种变种,主要是解决unicode书写不直观,语意不明确的问题。

与unicode使用方式相比,具备以下特色:

  • 兼容性良好,支持ie8+,及全部现代浏览器。
  • 相比于unicode语意明确,书写更直观。能够很容易分辨这个icon是什么。
  • 由于使用class来定义图标,因此当要替换图标时,只须要修改class里面的unicode引用。
  • 不过由于本质上仍是使用的字体,因此多色图标仍是不支持的。

使用步骤以下:

第一步:拷贝项目下面生成的fontclass代码:
//at.alicdn.com/t/font_8d5l8fzk5b87iudi.css
复制代码
第二步:挑选相应图标并获取类名,应用于页面:
<i class="iconfont icon-xxx"></i>
复制代码

symbol引用


这是一种全新的使用方式,应该说这才是将来的主流,也是平台目前推荐的用法。这种用法实际上是作了一个svg的集合,与上面两种相比具备以下特色:

  • 支持多色图标了,再也不受单色限制。
  • 经过一些技巧,支持像字体那样,经过font-size,color来调整样式。
  • 兼容性较差,支持 ie9+,及现代浏览器。
  • 浏览器渲染svg的性能通常,还不如png。

使用步骤以下:

第一步:拷贝项目下面生成的symbol代码:
//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js
复制代码
第二步:加入通用css代码(引入一次就行):
<style type="text/css"> .icon { width: 1em; height: 1em; vertical-align: -0.15em; fill: currentColor; overflow: hidden; } </style>
复制代码
第三步:挑选相应图标并获取类名,应用于页面:
<svg class="icon" aria-hidden="true">
    <use xlink:href="#icon-xxx"></use>
</svg>
复制代码

以上三种使用姿式的优缺点相信你们都了解了,symbol这中使用方式就是本文的正题了,其实以前我是一直都使用font-class这种方式的(你们估计用这个的也不少),可是它有点麻烦,由于我每次迭代项目时,修改或者添加图标都要去从新下载一份新的包,还不支持多色图标,可是如今我觉决定换了它,由于get到了一种更好的方式,它就是symbol

symbol它支持多色图标,兼容性到ie9+,这也没什么,毕竟某e浏览器差很少凉透了,浏览器渲染svg性能这个也能够不用担忧,早在14年张鑫旭的一篇帖子 SVG Sprite介绍 完美诠释了svg sprite的工做方式,而且对其很看好,或许这就是大佬的眼光吧 - _ -

单纯使用iconfont官方那种symbol方式实际上是有点low的,实际开发中咱们能够结合项目,让他变得简单,接下来咱们就要进入本文正题,优雅使用icon了,哈哈哈,码这么多字,我太难了

项目中优雅使用icon

搭建环境获取图标

咱们使用vue-cli3搭建项目

怎么样才算优雅,首先咱们在src目录下新建icons/文件夹,在icons/文件夹下建svg/文件夹,未来咱们项目中的svg图标都会统一放在这里

接下来咱们在官网搞来一个svg图标

no1

点击svg下载到icons/svg目录下修改文件名为qq.svg,或者是在icons/svg目录下新建一个qq.svg文件,把复制的svg代码放进去也能够

这样就获取到了一个图标,很easy

处理svg图标

vue-cli对svg文件有默认的url-loader 处理,咱们要使用svg 图标需单独进行配置

下载一个插件svg-sprite-loader来单独处理咱们的svg图标,它是一个webpack loader,支持将多个svg打包成svg sprites

npm下载

npm install svg-sprite-loader -D
复制代码

yarn下载

yarn add svg-sprite-loader -D
复制代码

咱们要怎么使用它呢,首先咱们不能覆盖原有的svg解析loader,咱们只须要把icons/svg这个文件夹下的svg文件解析打包便可,咱们在vue.config.js中chainWebpack函数中配置,来看代码

// 内置路径包
const path = require("path");

// 定义resolve方法,获取绝对路径
function resolve(dir) {
  return path.join(__dirname, dir);
}

module.exports = {
  // 一个函数,会接收一个基于 webpack-chain 的 ChainableConfig 实例
  // 容许对内部的 webpack 配置进行更细粒度的修改
  chainWebpack: config => {
    // 配置svg默认规则排除icons目录中svg文件处理
    config.module
      .rule("svg")
      .exclude.add(resolve("src/icons"))
      .end();

    // 新增icons规则,设置svg-sprite-loader处理icons目录中svg文件
    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();
  }
}
复制代码

若是咱们不清楚cli的默认配置,怕改错,可经过vue inspect审查webpack内部配置,详细请看: inspect使用

上面代码中咱们使用了webpack的链式高级用法来处理loader,首先排除了默认svg的loader对咱们icons/目录下svg文件的处理,而后新增了一个规则让svg-sprite-loader处理咱们icons/文件夹下的svg文件,最后咱们设置了icon-加上通过处理的svg文件名做为symbolId,也就是说咱们在使用qq.svg时能够直接在use标签使用#icon-qq,关于链式操做不了解的小伙伴能够看: 链式操做(高级)

代码中咱们引入了path这样一个内置的包,定义了一个resolve方法,该方法主要是来获取文件绝对路径的,咱们把使用路径的地方都使用该方法转为绝对路径,固然使用相对路径也是能够的,可是不太安全,平台解析相对路径有差别性,因此绝对路径是最安全的

svg sprites图标使用

如今咱们就能够在你想使用图标的位置使用了,使用方式以下

main.js中引入(全局引入)要使用的图标文件

import "@/icons/svg/qq.svg";
复制代码

模版中使用

<svg>
  <use xlink:href="#icon-qq"></use>
</svg>
复制代码

你觉得这就完了?不,还远远不够,这样使用一个图标就得引入文件一次也太麻烦了,接着看下文

进阶-svg文件自动引入

知道为何在icons/文件夹下还有一个存放svg文件的svg/文件夹吗,就是为了这一步自动化引入准备的,咱们在icons/文件夹下新建index.js文件,两行代码搞定,内容以下

// icons图标自动加载
const req = require.context("./svg", false, /\.svg$/);
req.keys().map(req);
复制代码

上面代码中咱们使用require.context设置了当前目录下的./svg文件为上下文,使用正则匹配了它须要检测的文件名,这样它就会在当前目录的svg文件夹下去匹配符合规则的文件名

而后咱们使用req.keys拿到全部文件名数组,再使用map遍历加载req方法,这样当该文件被调用时会遍历加载全部匹配到的文件,这就很nice了

看看咱们改进后的使用方法:

注释掉以前的代码,在main.js中引入icons/index.js文件

import "@/icons/index.js";
复制代码

模板中使用和上面同样,不过此次改进当咱们再次下载了一个svg图标时,不用再引入一遍图标svg了,由于咱们作了自动化,icons/svg/下的svg后缀图标文件均可被自动引入

<svg>
  <use xlink:href="#icon-qq"></use>
</svg>

<svg>
  <use xlink:href="#icon-wx"></use>
</svg>
...
复制代码

是否是很方便,你觉得结束了?不,咱们还能够再简化,由于每次使用都得svg标签包着use太麻烦了,写着也不太雅观,咱们继续简化,必定要看起来使用起来都十分优雅

再进阶-SvgIcon组件

components/目录下新建SvgIcon/index.vue文件,咱们写一个svgicon组件,封装一下再全局注册,这样使用起来就会很方便了!

svg-icon组件代码以下:

<template>
  <svg :class="svgClass" aria-hidden="true" v-on="$listeners">
    <use :xlink:href="iconName" />
  </svg>
</template>
<script> export default { name: "SvgIcon", props: { iconClass: { type: String, required: true }, className: { type: String, default: "" } }, computed: { iconName() { return `#icon-${this.iconClass}`; }, svgClass() { if (this.className) { return "svg-icon " + this.className; } else { return "svg-icon"; } } } }; </script>
<style scoped> .svg-icon { width: 1em; height: 1em; vertical-align: -0.15em; fill: currentColor; overflow: hidden; } </style>

复制代码

固然组件内部咱们还能够根据自身项目状况进行扩展,我这边写了基础的配置

组件写好了以后咱们在icons/index.js中进行全局注册,这样咱们只引入这一个文件就能够达到自动加载和组件注册两个功能

icons/index.js改进以下:

import Vue from "vue";
import SvgIcon from "@/components/SvgIcon";

// icons图标自动加载
const req = require.context("./svg", false, /\.svg$/);
req.keys().map(req);

// 全局注册svg-icon组件
Vue.component("svg-icon", SvgIcon);

复制代码

最后就是咱们的使用了,在main.js文件引入icons/index.js

import "@/icons/index.js";
复制代码

再来看看咱们使用图标的方法,组件中:

<template>
  <svg-icon icon-class="qq" class-name="qq-style"></svg-icon>
</template>
复制代码

看,咱们只用在icon-class中传入要使用的图标文件名就能够了,固然class-name还能够传入一个类,进行一些简单的样式修改,是否是很优雅,你get到了吗?

码字不易,动动小手,给个关注,点个赞啥的,哈哈

已尽可能通俗解释,保证无错,奈何水平有限,欢迎指错

做者:isboyjc

邮箱:214930661@qq.com

GitHub: github.com/isboyjc

参考文章:

将来必热:SVG Sprites技术介绍-张鑫旭

手摸手,带你优雅的使用 icon-掘金

相关文章
相关标签/搜索