使用 svg-sprite-loader、svgo-loader 优化 svg symbols

简介: 使用 svg-sprite-loader、svgo-loader 优化 svg symbols

     最近重新学习了一遍 React 基础,新起了个小 Demo 实践一下,项目中用到的静态资源也比较少,图标当时使用的是 svg symbols 的方式引入(字体图标三种格式区别),但是在开发的过程中遇到几个问题:


① 下载的 svg 可能有自带的 fill 属性,添加 color 样式不生效。

② 封装 Icon 组件时,每用到一个 svg 图标都需要引入一下,显得有点不太聪明。

       为解决上述两个问题,上网找了一下解决方案,在这里总结一下,每天成长一点点。

1、svg 的基本使用

       SVG :可缩放矢量图形(Scalable Vector Graphics),使用 XML 格式定义图像。使用起来其实也没什么不一样的地方,可以直接将下载好的 svg 图片导入,然后像这样使用:

import apple from "../assets/icons/apple.svg"  // 得到一个计算之后的路径
const Icon = (props) => {
    return (
        <img src={apple} />
    );
};
export default Icon;

      这样使用可能会导致上面所说的问题 虽然可以手动把 svg 图片中的 fill 属性给删掉,但是如果 svg 很多的话手动处理起来就会很耗时,我们可以通过更聪明的办法:自定义 loader 来解决这个问题,如下。

2、svg-sprite-loader

       svg-sprite-loader 的官方解释是:一个用于创建 svg 雪碧图的 Webpack 加载器。这个加载器现在已经被 JetBrains 公司收录和维护了。通俗的讲:svg-sprite-loader 会把你引入的 svg 塞到一个个 symbol 中,合成一个大的 svg,最后将这个大的 svg 放入 body 中。symbol 的 id 如果不特别指定,就是你的文件名。在页面上形成这样的元素:

<body>
    <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"
                xmlns:xlink="http://www.w3.org/1999/xlink"
                class="icon" viewBox="0 0 1024 1024"
                id="label">
            <defs><style type="text/css"></style></defs>
            <!-- path ... (path 中可能含有 fill 属性,也就是 svg 的自带颜色) -->
        </symbol>
        <!-- other symbols-->
    </svg>
</body>

       通常情况下,我们用脚手架初始化的项目是没有办法自定义 loader 的,那怎么办呢?我们就需要执行如下命令手动的项目的 webpack.config.js 文件搞出来(这个操作是不可逆的)。

npm run eject
// or
yarn eject

       执行会出现提示:Are you sure you want to eject? This action is permanent.(y/N)。直接就可以了。配置完成之后我们需要对 svg loader 进行相关配置,在 webpack.config.js 的 module.rules  的 oneOf 中添加:

// 配置之前需要安装该 loader
// npm install --dev svg-sprite-loader
// yarn add --dev svg-sprite-loader
{
  test: /\.svg$/,
  use: [
    { loader: 'svg-sprite-loader', options: {} }
  ]
}

       完成上述配置之后,我们就可以通过指定 id 的方式使用 use 的方式使用 svg 了,如下:

// 下面这种方式有坑,最终会被 Tree Shaking
// import apple from "../assets/icons/apple.svg"  // 得到一个计算之后的路径
require('../assets/icons/apple.svg')
const Icon = (props) => {
    return (
        <svg fill="red">
            <use xlink:href="#apple"/>
        </svg>
    );
};
export default Icon;

       而且经过 svg-sprite-loader 加载之后,不仅可以通过指定 id 的方式引入 icon,而且相比图片引入的方式,最大的优点就在于可以通过给 svg 标签添加 fill 属性来调整 icon 的颜色。


       除此之外,还可以通过给 svg 添加 class 来调整 icon 的样式,虽然说图片引入的方式也能做到,但是如果图片指定宽高与原图的宽高不成比例,就会导致图片的失真,而 svg 不会。即使随意调整 svg 的宽高样式,它也是按照原尺寸进行缩放,达到高保真的效果。


       🚨:注意,如果你按照上面 import 的方式引入了 svg ,在页面上是找不到 icon 的。这是因为 import 引入的 apple 实际上是一个对象,通过 svg use 指定的 #id 的方式最终被 webpack 理解为 apple 对象没被用到,所以就 Tree Shaking 掉它,因此我们需要用 require 的方式引入(原因:CommonJS 模块的这种动态加载的性质意味着无法应用 Tree Shaking,因为在实际运行代码之前无法确定需要哪些模块)。

3、批量引入 svg

       项目中我们用到 svg 的地方,都需要手动引入一下然后使用,当 svg 多起来的时候,一遍遍的引入就显得不太聪明。能不能像 Element UI 那样,直接指定一个 name 就能使用特定的 svg ?那就需要在 Icon 组件中将所有的 svg 做批量的引入:

// require('../assets/icons/apple.svg')
// require('../assets/icons/banana.svg')
// require('../assets/icons/orange.svg') // 这样就仿佛一个不太聪明的机器人
//直接引入 src/assets/icons 目录下的所有 svg
const importAll = (requireContext: __WebpackModuleApi.RequireContext) => {
    requireContext.keys().forEach(requireContext);
}
try {
    importAll(require.context('../assets/icons', true, /\.svg$/));
} catch (error) {
    console.log(error);
}
const Icon = (props) => {
    return (
        <svg>
          <use xlinkHref={'#' + props.name}></use>
        </svg>
    );
};
export default Icon;

       直接从网上拷贝上述代码会报错,需要 yarn add @types/webpack-env -D 一下。

4、svgo-loader

      等一下,还没有结束,刚才 svg-sprite-loader 可以帮助我们通过 svg use + 指定 id 的方式引入 svg,虽然可以通过给 svg 添加内联 fill 属性的方式修改 icon 的颜色,但是并不建议这样做,而是通过 class 样式的方式指定 icon 的颜色,这就需要用到 svgo-loader 先把 svg 自带的 fill 属性给清除掉,为我们后续指定 icon 的颜色扫清障碍。


       svgo-loader 是基于 SVG Optimizer 的一个加载器,而 SVG Optimizer 是一个基于node.js 的工具,用于优化 SVG 矢量图形文件,它可以删除和修改SVG元素,折叠内容,移动属性等。


       继续配置 webpack.config.js

// 配置之前需要安装该 loader
// npm install --dev svgo-loader
// yarn add --dev svgo-loader
{ loader: 'svg-sprite-loader', options: {} },
{ loader: 'svgo-loader', options: {
    plugins: [{
        name: 'removeAttrs', // 必须指定name!
        params: {attrs: 'fill'}
        }]
    }
}

        通过上述配置,引入项目中的 svg 文件会先经过 svgo-loader 清楚 fill 属性,然后再通过 svg-sprite-loader 将你引入的 svg 塞到一个个 symbol 中,合成一个大的 svg,最后将这个大的 svg 放入 body 中。

目录
相关文章
|
4月前
|
JSON 前端开发 JavaScript
vite中静态资源(css、img、svg等)的加载机制及其相关配置
【8月更文挑战第3天】vite中静态资源(css、img、svg等)的加载机制及其相关配置
495 1
|
5月前
|
编解码 缓存 前端开发
什么是CSS Sprite
【7月更文挑战第14天】 **CSS Sprite** 是一种图像合并技术,通过将多个图标整合到一张大图并利用CSS背景定位显示所需部分,减少HTTP请求,提升页面加载速度和降低服务器压力。优点包括减少请求次数、降低服务器负担、加快速度和简化图片管理,但制作与维护成本高且定位复杂。使用工具可降低工作难度,适应不同分辨率设备。需权衡利弊适时应用。
51 1
|
5月前
|
前端开发
css【详解】steps()函数
css【详解】steps()函数
36 1
|
前端开发
CSS中transform的使用
CSS中transform的使用
107 1
|
XML 前端开发 JavaScript
使用 svg-sprite-loader 批量引入 icon
使用 svg-sprite-loader 批量引入 icon
234 0
|
缓存 前端开发 JavaScript
【前端】style-loader和MiniCssExtractPlugin.loader
【前端】style-loader和MiniCssExtractPlugin.loader
241 0
|
资源调度 前端开发 JavaScript
4、处理css文件(css-loader加载器与mini-css-extract-plugin分离CSS文件插件)
4、处理css文件(css-loader加载器与mini-css-extract-plugin分离CSS文件插件)
231 0
|
前端开发 JavaScript 开发者
loader - 配置处理 css 样式表的第三方 loader| 学习笔记
快速学习 loader - 配置处理 css 样式表的第三方 loader
|
前端开发
CSS - CSS Sprites Generator(雪碧图)
CSS - CSS Sprites Generator(雪碧图)
113 0
CSS - CSS Sprites Generator(雪碧图)