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 相关文章推荐
JS和Jquery获取和修改label的值的示例代码
Jan 15 Javascript
JavaScript表单验证实例之验证表单项是否为空
Jan 10 Javascript
WordPress中利用AJAX技术进行评论提交的实现示例
Jan 12 Javascript
Angularjs 实现分页功能及示例代码
Sep 14 Javascript
JavaScript获取服务器时间的方法详解
Dec 11 Javascript
jquery实现左右轮播图效果
Sep 28 jQuery
Thinkjs3新手入门之如何使用静态资源目录
Dec 06 Javascript
AngularJS标签页tab选项卡切换功能经典实例详解
May 16 Javascript
Vue多系统切换实现方案
Jun 05 Javascript
用jQuery将JavaScript对象转换为querystring查询字符串的方法
Nov 12 jQuery
vue动态子组件的两种实现方式
Sep 01 Javascript
jQuery实现的上拉刷新功能组件示例
May 01 jQuery
使用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 获取客户端的真实ip
2009/11/30 PHP
php-redis中的sort排序函数总结
2015/07/08 PHP
PHP函数func_num_args用法实例分析
2015/12/07 PHP
Javascript 中介者模式实例
2009/12/16 Javascript
Jquery 高亮显示文本中重要的关键字
2009/12/24 Javascript
基于Jquery的表格隔行换色,移动换色,点击换色插件
2010/12/22 Javascript
JS常用正则表达式总结
2013/11/12 Javascript
JavaScript使用pop方法移除数组最后一个元素用法实例
2015/04/06 Javascript
jQuery判断一个元素是否可见的方法
2015/06/05 Javascript
JS实现超简单的仿QQ折叠菜单效果
2015/09/21 Javascript
javascript实现无缝上下滚动特效
2015/12/16 Javascript
浅析BootStrap模态框的使用(经典)
2016/04/29 Javascript
Vue单文件组件基础模板小结
2017/08/10 Javascript
Nodejs异步回调之异常处理实例分析
2018/06/22 NodeJs
微信小程序用户信息encryptedData详解
2018/08/24 Javascript
Vue 页面状态保持页面间数据传输的一种方法(推荐)
2018/11/01 Javascript
简述pm2常用命令集合及配置文件说明
2019/05/30 Javascript
Vue Element UI + OSS实现上传文件功能
2019/07/31 Javascript
解决layui富文本编辑器图片上传无法回显的问题
2019/09/18 Javascript
layui table 表格模板按钮的实例代码
2019/09/21 Javascript
[01:59][TI9趣味视频] 全明星赛奖励
2019/08/23 DOTA
python自动化测试之连接几组测试包实例
2014/09/28 Python
python实现的系统实用log类实例
2015/06/30 Python
详解python的几种标准输出重定向方式
2016/08/15 Python
Python利用WMI实现ping命令的例子
2019/08/14 Python
python中property属性的介绍及其应用详解
2019/08/29 Python
python 基于dlib库的人脸检测的实现
2019/11/08 Python
使用python切片实现二维数组复制示例
2019/11/26 Python
Spring实战之使用util:命名空间简化配置操作示例
2019/12/09 Python
在keras 中获取张量 tensor 的维度大小实例
2020/06/10 Python
html5写一个BUI折叠菜单插件的实现方法
2019/09/11 HTML / CSS
宿舍使用违章电器检讨书
2014/01/12 职场文书
小学三年级数学教学反思
2014/01/31 职场文书
企业优秀团员事迹材料
2014/08/20 职场文书
2014年村党支部工作总结
2014/12/04 职场文书
MySQL 逻辑备份与恢复测试的相关总结
2021/05/14 MySQL