如何展示一个icon

前言

最近开发的时候被icon烦到了,之前都用的是antd或者ele的图标,就这个写法

<i class="el-icon-share"></i>

或者阿里矢量库的图标也基本是这么个用法。
但是这次的新项目不用这些,要用他们自己封装的组件,我一直没整明白(然后就都用img,不同颜色就得再下一张图,实在蠢),今天抽个时间理一下。东西有点多,一点一点来吧~

先搞清楚几个概念

1. use

use元素在SVG文档内取得目标节点,并在别的地方复制它们。它的效果等同于这些节点被深克隆到一个不可见的DOM中,然后将其粘贴到use元素的位置

2. symbol

symbol元素用来定义一个图形模板对象,它可以用一个<use>元素实例化。symbol元素对图形的作用是在同一文档中多次使用,添加结构和语义。结构丰富的文档可以更生动地呈现出来,类似讲演稿或盲文,从而提升了可访问性。注意,一个symbol元素本身是不呈现的。只有symbol元素的实例(亦即,一个引用了symbol<use>元素)才能呈现。

3. 雪碧图

3.1. CSS sprite

传统的CSS sprite是将多个icon整合到一张图中,然后通过定位获取其中的某个图标。
优点:减少网络请求
缺点:无法更改图标的样式,高分辨率下会模糊
举个例子,百度首页搜索框里的图标就是用雪碧图做的。
可以看到一共四个小icon,有灰有蓝,蓝的就是hover上去显示的图片,看样式就可以发现,他是通过调整图片位置(background-position),来显示不同图标的。这样原本四个图,需要4次HTTP请求,现在就只需要一次了。


雪碧图

百度搜索框

3.2. SVG sprite

这里就要用到我们开头说的两的标签,<symbol>+<use>。
首先利用symbol定义图形模板对象,然后使用use,找到该对象的引用进行复用,symbol元素有一个id属性,使用use时,给use的href属性'#'+id就可以找到对应的引用。
下面是一个参考1中的一个例子SVG Sprite使用示意的截图

示例1

接下来的问题就是如何将svg图片转成symbol标签整合在一起呢
我们项目是通过svg-sprite-loader来实现的。

3.3. svg-sprite-loader

先安装

yarn add svg-sprite-loader -D -S

在vue.config.js中配置

const path = require('path')
const _ = require('lodash')
module.exports = {
    chainWebpack: (config) => {
        addSvgSpriteLoaderConfig(config)
    }
}
function addSvgSpriteLoaderConfig(config) {
    const svgDirs = [
        // 自定义的 svg 文件夹
        path.resolve(__dirname, './src/assets/test/'),
    ]
    /**
     * 根据 svg 相对路径(相对 dirs 中配置的文件夹路径)生成 symbol id
     */
    function symbolId(filePath) {
        // console.log('cyy', filePath)
        const path = svgDirs.reduce((path, dir) => {
            return (path = path.replace(dir, ''))
        }, filePath)
        const name = path.replace('.svg', '')
        const res =  _.upperFirst(_.camelCase(name))
        console.log('res', res)
        return res
    }
    config.module.rule('svg').exclude.add(svgDirs).end()
    config.module
        .rule('icons')
        .test(/\.svg$/)
        .include.add(svgDirs) //处理svg目录
        .end()
        .use('svg-sprite-loader')
        .loader('svg-sprite-loader')
        .options({
            symbolId,
        })
    // config.module.rule('svg-sprite-loader').use('svgo-loader').loader('svgo-loader')
}

但是配置完启动之后,发现body下面并没有svg标签,console了一下发现根本没进symbolId方法,但是addSvgSpriteLoaderConfig方法是走了的。尝试了一下使用,发现出现svg标签了

import '../assets/test/upgrade.svg'
import '../assets/test/target.svg'
...
    <svg>
      <use xlink:href="#Upgrade"></use>
    </svg>
    <svg>
      <use href="#Target"></use>
    </svg>
示例2

说明只有引入了svg,才会经过svg-sprite-loader

3.4. 颜色填充

在项目中使用时,只需要在svg标签上设置color,就能改变icon的颜色,这一点一直让我觉得很神奇,理论上需要通过设置fill,才能改变颜色,后来我发现是因为svg上设置了这一句样式:

 fill: currentColor

currentColor就是使用当前该元素所处环境的文字颜色,所以设置color相当于设置了fill。

Z、参考

1 未来必热:SVG Sprites技术介绍
2 # 懒人神器:svg-sprite-loader实现自己的Icon组件
3 SVG进阶-sprite 雪碧图
4 SVG图标颜色文字般继承与填充
5 Cascading SVG Fill Color
6 https://juejin.cn/post/6844903695478439949

12月1日始
12月6日发布第一稿

luffy.jpeg

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 我们都知道SVG替代图片作为图标的好处,但如何能够方便的加载在VUE工程中呢;通过直接插入SVG代码方式画,当然是...
    随机昵称阅读 6,483评论 0 0
  • 使用之前我们 react + typescript 搭建的脚手架来写我们第一个也是最简单的 Icon 组件 开发U...
    YM雨蒙阅读 5,375评论 0 2
  • 知识点1、自己使用webpack搭建项目配置webpack是增加webpack.config.js2、vue/cl...
    浅浅_2d5a阅读 3,730评论 0 0
  • 前言 本篇文章其实陆陆续续写了快半年,主体部分写好了很久了,但由于种种原因一直没有发布。首先来说说写这篇文章的主要...
    7cd975786ccd阅读 9,913评论 0 11
  • 前言 React 的UI框架 Ant Design 在 3.9.0版本之后,使用 SVG 图标替换了原先的 f...
    回调的幸福时光阅读 6,109评论 0 0