Webpack中雪碧图插件使用详解


Posted in Javascript onMay 25, 2018

背景

在开发过程中,我们需要用到很多图标,这些图标的大小不是很大,但是每次需要向服务器发送请求,从而加重服务器的负担,尤其是当网站处于高访问量的情况下或网络不稳定的时候,服务器性能会明显下降。这种情况不符合被广泛遵循的雅虎军规“尽量减少HTTP请求数”的要求(雅虎前端优化的35条军规)。

为了避免这种情况,我们需要使用到雪碧图将这些图标整合到一张图片上,再使用CSS背景及其定位,将需要显示的图标移动到元素背景中。

传统方式,我们需要将图标拼接到一张图片上,计算好位置信息,这种方式维护起来比较麻烦。自从有了打包工具grunt、gulp和webpack之后,这一切似乎容易了许多。这里我重点介绍webpack雪碧图插件webpack-spritesmith的使用。

雪碧图插件 webpack-spritesmith 详解

本人是在 vue-cli 中增加了该雪碧图插件,关键步骤如下,细节上以 vue-cli 为背景,其他框架类似配置。

1. 安装配置

首先在项目中按照官方说明 install 之后,在 bulid/webpack.base.conf.js 中进行如下配置。需要说明的是,雪碧图是开发模式和生产模式都要使用的功能,因此我们在 webpack 的基础配置中进行设置。

1.1 首先引入插件 const SpritesmithPlugin = require('webpack-spritesmith');;

1.2 其次在 module.rules 将 png 图标的默认配置注释掉,避免 url-loader 将其编译成行内图片,同时单独设置 png 图标的配置,如下:

{
 // test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, // 注释掉原有配置,去掉对png图标的匹配
 test: /\.(jpe?g|gif|svg)(\?.*)?$/,
 loader: 'url-loader',
 options: {
  limit: 10000,
  name: utils.assetsPath('img/[name].[hash:7].[ext]')
 }
},
// 对图标单独设置,以便生成雪碧图
{
 test: /\.png$/,
 loaders: [
  'file-loader' // 使用 file-loader 对 png 图标进行设置
 ]
},

1.3 接着在 webpack 的配置对象中找到 plugins 属性(没有请自行创建),添加雪碧图的处理。基本配置如下:

plugins: [
 // 雪碧图设置
 new SpritesmithPlugin({
  src: {
   cwd: path.resolve(__dirname, '../src/assets/images/icons/'), // 图标根路径
   glob: '**/*.png' // 匹配任意 png 图标
  },
  target: {
   image: path.resolve(__dirname, '../src/assets/css/sprites-generated.png'), // 生成雪碧图目标路径与名称
   // 设置生成CSS背景及其定位的文件或方式
   css: [
    [path.resolve(__dirname, '../src/assets/css/sprites-generated.css'), {
     format: 'function_based_template'
    }]
   ]
   // css: path.resolve(__dirname, '../src/assets/spritesmith-generated/sprite.less')
  },
  customTemplates: {
   'function_based_template': templateFunction,
  },
  apiOptions: {
   cssImageRef: "./sprites-generated.png", // css文件中引用雪碧图的相对位置路径配置
  },
 })
],

这里我使用的是CSS定制方式,即在 target.css 中,配置对应的format函数名 function_based_template(注意数组元素的层次关系,切勿配错)。然后在 customTemplates 中配置对应名称的属性名。

这里我引用了自定义函数 templateFunction,该函数基本参考了官方示例。由于本人使用的是二倍图,所以此处使用了图片缩放和垂直居中的方式。大家选择参考:

const templateFunction = function (data) {
 // console.log(data.sprites);
 const shared = '.w-icon { background-image: url(I); }'
   .replace('I', data.sprites[0].image);
 // 注意:此处默认图标使用的是二倍图
 const perSprite = data.sprites.map(function (sprite) {
  // background-size: SWpx SHpx;
  return '.w-icon-N { width: SWpx; height: SHpx; }\n.w-icon-N .w-icon, .w-icon-N.w-icon { width: Wpx; height: Hpx; background-position: Xpx Ypx; margin-top: -SHpx; margin-left: -SWpx; } '
   .replace(/N/g, sprite.name)
   .replace(/SW/g, sprite.width / 2)
   .replace(/SH/g, sprite.height / 2)
   .replace(/W/g, sprite.width)
   .replace(/H/g, sprite.height)
   .replace(/X/g, sprite.offset_x)
   .replace(/Y/g, sprite.offset_y);
 }).join('\n');

 return shared + '\n' + perSprite;
};

其实关键之处就是利用定制函数,将参数中每个图标的信息用来进行样式的定制。这些信息中包括图标名、宽高和在雪碧图中的位置信息等。

当然我们也可以将目标生成成 less 文件,然后再进行使用(示例代码中注释部分)。但本人发现会生成大量变量,而这些变量我们并不经常使用,所以本人没有采用这种方式。

2. 使用方法

进行完上述配置之后,再在我们配置的源文件夹中添加我们需要处理的图标。然后启动 vue-cli 的开发者模式 npm run start(其他框架,运行对应命令)。

启动完成之后,我们可以发现在目标目录下生成了 sprites-generated.png 和 sprites-generated.css 两个文件。在样式文件中,形如:

.w-icon { background-image: url(./sprites-generated.png); }
.w-icon-apply { width: 25.5px; height: 27px; }
.w-icon-apply .w-icon, .w-icon-apply.w-icon { width: 51px; height: 54px; background-position: -208px -58px; margin-top: -27px; margin-left: -25.5px; }

接下来就是在使用组件中引用上述样式即可。

3.遇到的问题

3.1 放大页面时,有些雪碧图标边缘出现相邻图标的边缘,从而出现白线,怎么破?

做完雪碧图之后,高高兴兴的拿给UI参看一下,没过多久就被鄙视了:怎么页面放大时,旁边有一条白线?
纳尼?怎么可能啊!仔细一看,放大之后有些图标周边出现一些线条,而有些图标则没有。而不放大时,则没有这种情况。
难道是其他图表也显示进来了?再回去看看生成的雪碧图,果然是一个图标一个图标的紧紧的靠在一起,即图标之间没有空隙。而且有些图标计算的结果有 .5px ,我们知道有些浏览器会解析成1px,从而出现上述问题,瞬间恍然大悟。
于是仔细翻阅官方说明,其中提到核心组件是 spritesmith and spritesheet-templates ,于是进入 spritesmith 插件中查阅,发现果然有关于边距问题的描述和解决方法 spritesmith: padding。

可是在 webpack-spritesmith 又该怎么使用呢?

查阅 webpack-spritesmith 源代码和文档,发现:spritesmithOptions - optional. Options for spritesmith

好的,就是你啦!然后在 webpack 配置文件中,增加 padding 属性,这里单位为 px:

plugins: [
  // 雪碧图设置
  new SpritesmithPlugin({
   // ... 省略其他配置
   // 核心组件配置
   spritesmithOptions: {
    padding: 4,
   }
  })
 ],

重新启动项目编译,打开雪碧图和样式,发现图标之间有间隙了,且放大页面后,图标边缘也没有出现白线问题。好了,搞定!

总结

有了这个插件之后,我们就可以在配置目录下动态添加图标,此时webpack 会立即重新编译生成新的雪碧图和对应样式,这样我们就可以在页面上立刻使用对应图标,再也不用担心自己设置的 background-position 有不对的地方了。好了,Have Fun!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
document.designMode的功能与使用方法介绍
Nov 22 Javascript
js实现在文本框光标处添加字符的方法介绍
Nov 24 Javascript
js中substr,substring,indexOf,lastIndexOf的用法小结
Dec 27 Javascript
JavaScript使用replace函数替换字符串的方法
Apr 06 Javascript
基于jQuery仿淘宝产品图片放大镜代码分享
Jun 23 Javascript
javascript截图 jQuery插件imgAreaSelect使用详解
May 04 Javascript
JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)
Dec 14 Javascript
十大热门的JavaScript框架和库
Mar 21 Javascript
分享vue.js devtools遇到一系列问题
Oct 24 Javascript
详解如何将 Vue-cli 改造成支持多页面的 history 模式
Nov 20 Javascript
JavaScript面试出现频繁的一些易错点整理
Mar 29 Javascript
解决vue打包后刷新页面报错:Unexpected token
Aug 27 Javascript
使用javascript做在线算法编程
May 25 #Javascript
JS实现的汉字与Unicode码相互转化功能分析
May 25 #Javascript
浅析node.js的模块加载机制
May 25 #Javascript
webpack4的迁移的使用方法
May 25 #Javascript
最后说说Vue2 SSR 的 Cookies 问题
May 25 #Javascript
详解webpack4多入口、多页面项目构建案例
May 25 #Javascript
js中的 || 与 && 运算符详解
May 24 #Javascript
You might like
PHP调用接口API封装的例子
2019/10/11 PHP
基于jQuery的ajax功能实现web service的json转化
2009/08/29 Javascript
jquery获取ASP.NET服务器端控件dropdownlist和radiobuttonlist生成客户端HTML标签后的value和text值
2010/06/28 Javascript
ajax页面无刷新 IE下遭遇Ajax缓存导致数据不更新的问题
2012/12/11 Javascript
ExtJs中gridpanel分组后组名排序实例代码
2013/12/02 Javascript
JQuery $.each遍历JavaScript数组对象实例
2014/09/01 Javascript
《JavaScript DOM 编程艺术》读书笔记之JavaScript 简史
2015/01/09 Javascript
基于nodejs+express(4.x+)实现文件上传功能
2015/11/23 NodeJs
js和jq使用submit方法无法提交表单的快速解决方法
2016/05/17 Javascript
关于网页中的无缝滚动的js代码
2016/06/09 Javascript
a标签置灰不可点击的实现方法
2017/02/06 Javascript
第一次记录Bootstrap table学习笔记(1)
2017/05/18 Javascript
vue项目总结之文件夹结构配置详解
2017/12/13 Javascript
使用jQuery动态设置单选框的选中效果
2018/12/06 jQuery
vue组件开发props验证的实现
2019/02/12 Javascript
layui表格数据复选框回显设置方法
2019/09/13 Javascript
jQuery实现高度灵活的表单验证功能示例【无UI】
2020/04/30 jQuery
Python中使用第三方库xlrd来读取Excel示例
2015/04/05 Python
TensorFLow用Saver保存和恢复变量
2018/03/10 Python
基于python实现聊天室程序
2018/07/27 Python
详解Python字典小结
2018/10/20 Python
pygame实现五子棋游戏
2019/10/29 Python
python中的Elasticsearch操作汇总
2019/10/30 Python
使用python写一个自动浏览文章的脚本实例
2019/12/05 Python
Scrapy爬虫文件批量运行的实现
2020/09/30 Python
Python实现定时监测网站运行状态的示例代码
2020/09/30 Python
python opencv实现图像配准与比较
2021/02/09 Python
高校学生干部的自我评价分享
2013/11/04 职场文书
学习十八大的心得体会
2014/09/01 职场文书
房产协议书范本2014
2014/09/30 职场文书
个人整改措施落实情况汇报
2014/10/29 职场文书
2015年政府采购工作总结
2015/05/21 职场文书
卖车协议书范文
2016/03/23 职场文书
穷人该怎么创业?谨记以下几点
2019/07/11 职场文书
聊聊SpringBoot自动装配的魔力
2021/11/17 Java/Android
Win11 S Mode版本泄露 正式上线后叫做Windows 11 SE
2021/11/21 数码科技