svg-sprite图标技术

152 阅读2分钟

一 svg-sprite 图标的使用

1 进行 webpack 的配置

webpack.config.js:

module: {
  rules: [
    {
      test: /.svg$/,
      use: [{
        loader: 'svg-sprite-loader',
        options: {
          symbolId: 'xxx-yyy-[name]-zzz'
        }
      }]
    }
  ]
}

注意这里的 symbolId,最好配置一个比较全局唯一的名称。因为这里的 id,后面会作为 这个 html 标签的 id,存在于全局 DOM 当中。

2 在项目中引入 svg 资源

--1 首先在项目 src 目录下创建一个 svgs 目录,这里统一存放项目的 svg 图标资源。

--2 然后去下载图标资源。需要在阿里 iconfont 图标库当中,选择一个具体的图标 -> 点击下载按钮 -> 选择好 svg 图标的尺寸 -> 选择复制 SVG 代码

--3 在 svgs 目录当中创建一个 svg 文件,根据自己的需要命名,然后将刚刚复制的 svg 代码,粘贴在这个 svg 文件当中。

注意之后需要将该 svg 文件当中的 fill="xxx" 改为 fill="currentColor"

这是为了后面能使用 svg 标签的 css-color 属性去设置该图标的颜色。

--4 然后在 svgs 目录中创建一个 index.js 文件,作为使用图标的统一入口。

该文件当中通过 import './xxx.svg' 的形式,将一个个 svg 图标资源文件引入到项目代码当中。

--5 最后在项目的入口文件 main.js 当中,通过 imoport './svgs' 引入所有的 svg 图标资源。

3 在项目中使用 svg 图标

代码:

<template>
<svg class="svg-icon" style="font-size: 50px; color: red;">
  <use xlink:href="#xxx-yyy-dede-zzz"></use>
</svg>
</template><style scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
</style>

svg-icon 作为 svg 图标的基础类,然后可以通过 font-size 这个 css 属性设置该图标的大小,通过 color 这个 css 属性设置该图标的颜色。

二 svg-sprite 图标技术的原理

1 svg-sprite-loader 的作用

--1 webpack 配置

module: {
  rules: [
    {
      test: /.svg$/,
      use: [{
        loader: 'svg-sprite-loader',
        options: {
          symbolId: 'xxx-yyy-[name]-zzz'
        }
      }]
    }
  ]
}

注意这里的 symbolId,最好配置一个比较全局唯一的名称。因为这里的 id,后面会作为 这个 html 标签的 id,存在于全局 DOM 当中。

--2 haha.svg 资源文件:

<svg
     t="1680534954770"
     class="icon"
     viewBox="0 0 1024 1024"
     version="1.1"
     xmlns="http://www.w3.org/2000/svg"
     p-id="1211"
     width="32"
     height="32"
>
    <path fill="currentColor"></path>
</svg>

--3 引入 svg 资源代码

import './haha.svg'

注意之后需要将该 svg 文件当中的 fill="xxx" 改为 fill="currentColor"

这是为了后面能使用 svg 标签的 css-color 属性去设置该图标的颜色。

--4 webpack 打包结果

dist/index.html:

<body>
    <div id="box"></div>
    <script src="/dist/js/main.6c8a5c9ea9.js"></script>
</body>

dist/js/main.6c8a5c9ea9.js:

var __webpack_modules__ = {
    "./node_modules/svg-baker-runtime/browser-symbol.js": function() {},
    "./node_modules/svg-sprite-loader/runtime/browser-sprite.build.js": function() {},
    "./src/svgs/haha.svg": function() {},
}

--5 运行打包后代码

之后在我们运行该打包后的代码时,svg-sprite-loader 中的这些 svg 辅助函数,会在全局 DOM 的 body 下面创建 svg-symbol 标签。注意:创建 svg 标签的行为,一定是在我们运行代码后,是 js 运行时去动态创建的。

代码运行后,DOM 结构变为这样:

<svg
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink"
     style="position: absolute; width: 0; height: 0"
     aria-hidden="true"
     id="__SVG_SPRITE_NODE__"
>
    <symbol
            xmlns="http://www.w3.org/2000/svg"
            class="icon"
            viewBox="0 0 1024 1024"
            id="xxx-yyy-haha-zzz"
    ></symbol>
</svg>

等于说就是把我们在源 svg 文件内容,变成了这里的一个个 symbol 标签。源 svg 文件内容当中 svg 标签上面的 class、viewBox 属性,现在都跑到 symbol 标签上面来了。最重要的是,会给每一个 symbol 标签,都加上一个 id 属性,且这个 id 属性的值,就是我们在 webpack 中给 svg-sprite-loader 配置的 symbolId 值。

之后我们就可以通过这个 symbol 标签的 id 值,来引用需要的图标了。

其实这里相当于是生成了 svg 图标资源的定义,或者说是生成了 svg 图标的资源池,之后在项目中所有地方,都可以通过 id 来引入需要的 svg 图标。

2 svg-sprite-loader 处理完图标资源后,图标的使用原理

--1 使用图标代码

<template>
<svg class="svg-icon" style="font-size: 50px; color: red;">
  <use xlink:href="#xxx-yyy-dede-zzz"></use>
</svg>
</template><style scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
</style>

--2 代码解析

使用 <svg><use xlink:href="#svg-icon-id"></use></svg> 代码来引用 svg 图标,这里的 svg 标签,才是真正的 svg 图标,是我们常规理解的 svg 图标标签。之前 svg-sprite-loader 生成的 svg-symbol 标签,只是 svg 图标的定义。

然后我们需要给项目中的所有使用 svg 图标地方的 svg 标签,加上一个基础 css 类,这里就是 svg-icon

这个基础类当中设置 width: 1em; height: 1em;,就是为了后面能够使用 font-size css 属性,来设置该 svg 标签的大小。

基础类中设置 fill: currentColor;,就是为了后面能够使用 color css 属性,来设置该 svg 标签的颜色。

三 svg-sprite 图标技术使用的优化

1 引入 svg 图标资源的优化

svgs/index.js:

// 将 ./svgs 目录下的所有 svg 文件进行打包
const context = require.context('./', false, /.svg$/)
​
// 获取 context key
const contextKeys = context.keys()
​
// 遍历 contextKeys
contextKeys.forEach(contetKey => {
  // 使用这个 key 调用对应模块, 这里不需要获取导出结果, 只需要调用就行了
  context(contetKey)
})
2 使用 svg 图标的优化

vue 组件 svg-icon.vue:

<template>
  <svg class="svg-icon" aria-hidden="true">
    <use :xlink:href="iconId"/>
  </svg>
</template><script>
export default {
  name: 'SvgIcon',
  props: {
    iconName: {
      type: String,
      required: true
    }
  },
  computed: {
    iconId() {
      return `#xxx-yyy-${this.iconName}-zzz`
    }
  }
}
</script><style scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
</style>

使用该组件

<svg-icon icon-name="haha" :class="'my-icon'"></svg-icon>
<svg-icon icon-name="xixi" class="my-icon"></svg-icon>
3 使用 svgo-loader 压缩 svg 文件内容

webpack.config.js:

{
    test: /.svg$/,
        use: [
            {
                loader: 'svg-sprite-loader',
                options: {
                    symbolId: 'xxx-yyy-[name]-zzz'
                }
            },
            'svgo-loader'
        ]
}
4 使用自定义 loader 处理 svg 文件当中的 fill="#xxxxxx"

--1 在项目根目录创建 webpack-loaders 目录

--2 创建 svg-color-transform-loader / index.js 文件

module.exports = function(content, map, meta) {
  return content.replace(/fill="#(\w{3}|\w{6})"/g, 'fill="currentColor"')
}

--3 修改 webpack 配置

webpack.config.js:

{
    test: /.svg$/,
        use: [
            {
                loader: 'svg-sprite-loader',
                options: {
                    symbolId: 'xxx-yyy-[name]-zzz'
                }
            },
            './webpack-loaders/svg-color-transform-loader',
            'svgo-loader'
        ]
}