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 相关文章推荐
JavaScript While 循环基础教程
Apr 05 Javascript
js模拟实现Array的sort方法
Dec 11 Javascript
Jquery知识点三 jquery表单对象操作
Jan 17 Javascript
javascript各浏览器中option元素的表现差异
Apr 07 Javascript
JS 退出系统并跳转到登录界面的实现代码
Jun 29 Javascript
jQuery检测返回值的数据类型
Jul 13 Javascript
通过正则表达式获取url中参数的简单实现
Jun 07 Javascript
Js获取当前日期时间及格式化代码
Sep 17 Javascript
js数组去重的hash方法
Dec 22 Javascript
详解Angular之constructor和ngOnInit差异及适用场景
Jun 22 Javascript
小程序实现搜索框功能
Mar 26 Javascript
Vue解析带html标签的字符串为dom的实例
Nov 13 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
js函数使用技巧之 setTimeout(function(){},0)
2009/02/09 Javascript
基于Jquery的$.cookie()实现跨越页面tabs导航实现代码
2011/03/03 Javascript
javascript实现原生ajax的几种方法介绍
2013/09/21 Javascript
jquery利用命名空间移除绑定事件的方法
2015/03/11 Javascript
Jquery实现鼠标移动放大图片功能实例
2015/03/25 Javascript
JavaScript简单下拉菜单实例代码
2015/09/07 Javascript
jQuery中Ajax全局事件引用方式及各个事件(全局/局部)执行顺序
2016/06/02 Javascript
js学习笔记之事件处理模型
2016/10/31 Javascript
javaScript语法总结
2016/11/25 Javascript
Vue 实用分页paging实例代码
2017/04/12 Javascript
js编写简单的计时器功能
2017/07/15 Javascript
jquery实现搜索框功能实例详解
2018/07/23 jQuery
详解解决小程序中webview页面多层history返回问题
2019/08/20 Javascript
js实现固定区域内的不重叠随机圆
2019/10/24 Javascript
Vue-cli assets SubDirectory及PublicPath区别详解
2020/08/18 Javascript
[02:36]DOTA2英雄基础教程 斯拉克
2013/11/29 DOTA
python中去空格函数的用法
2014/08/21 Python
在Python编程过程中用单元测试法调试代码的介绍
2015/04/02 Python
学习python 之编写简单乘法运算题
2016/02/27 Python
Python动刷新抢12306火车票的代码(附源码)
2018/01/24 Python
python 定时修改数据库的示例代码
2018/04/08 Python
Python实现求两个数组交集的方法示例
2019/02/23 Python
python web框架中实现原生分页
2019/09/08 Python
Python综合应用名片管理系统案例详解
2020/01/03 Python
Python实现序列化及csv文件读取
2020/01/19 Python
django ObjectDoesNotExist 和 DoesNotExist的用法
2020/07/09 Python
CSS3动画animation实现云彩向左滚动
2014/05/09 HTML / CSS
HTML5 Canvas+JS控制电脑或手机上的摄像头实例
2014/05/03 HTML / CSS
专门经营化妆刷的美国彩妆品牌:Sigma Beauty
2017/09/11 全球购物
Nike荷兰官方网站:Nike.com (NL)
2018/04/19 全球购物
GOLFINO英国官网:高尔夫服装
2020/04/11 全球购物
物业招聘计划书
2014/01/10 职场文书
营销总经理岗位职责
2014/02/02 职场文书
理财计划书
2014/08/14 职场文书
《唯一的听众》教学反思
2016/02/18 职场文书
2019下半年英语教师的教学工作计划(3篇)
2019/09/25 职场文书