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 相关文章推荐
jquery一般方法介绍 入门参考
Jun 21 Javascript
html的DOM中document对象forms集合用法实例
Jan 21 Javascript
javascript实现汉字转拼音代码分享
Apr 20 Javascript
基于bootstrap实现广告轮播带图片和文字效果
Jul 22 Javascript
jquery做个日期选择适用于手机端示例
Jan 10 Javascript
Vue2.0 UI框架ElementUI使用方法详解
Apr 14 Javascript
使用Xcache缓存器加速PHP网站的配置方法
Apr 22 Javascript
Vue2.0学习之详解Vue 组件及父子组件通信
Dec 12 Javascript
javascript实现考勤日历功能
Nov 29 Javascript
用vue写一个日历
Nov 02 Javascript
JS获取一个字符串中指定字符串第n次出现的位置
Feb 10 Javascript
Vue中foreach数组与js中遍历数组的写法说明
Jun 05 Vue.js
使用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 PDO中文乱码解决办法
2009/07/20 PHP
浅析HTTP消息头网页缓存控制以及header常用指令介绍
2013/06/28 PHP
PHP中替换键名的简易方法示例详解
2014/01/07 PHP
php实现的树形结构数据存取类实例
2014/11/29 PHP
php简单分页类实现方法
2015/02/26 PHP
php计算到指定日期还有多少天的方法
2015/04/14 PHP
用ADODB.Stream转换
2007/01/22 Javascript
js 返回时间戳所对应的具体时间
2010/07/20 Javascript
使用javascript创建快捷方式的简单实例
2013/08/09 Javascript
基于jquery实现的文字淡入淡出效果
2013/11/14 Javascript
JS获取文本框,下拉框,单选框的值的简单实例
2014/02/26 Javascript
AngularJS iframe跨域打开内容时报错误的解决办法
2015/01/26 Javascript
JavaScript时间转换处理函数
2015/04/14 Javascript
jquery层级选择器(匹配父元素下的子元素实现代码)
2016/09/05 Javascript
jQuey将序列化对象在前台显示地实现代码(方法总结)
2016/12/13 Javascript
js实现图片区域可点击大小随意改变(适用移动端)代码实例
2019/09/11 Javascript
jQuery设置下拉框显示与隐藏效果的方法分析
2019/09/15 jQuery
jquery+css3实现的经典弹出层效果示例
2020/05/16 jQuery
python 合并文件的具体实例
2013/08/08 Python
python使用urllib模块开发的多线程豆瓣小站mp3下载器
2014/01/16 Python
Python3中多线程编程的队列运作示例
2015/04/16 Python
python  文件的基本操作 菜中菜功能的实例代码
2019/07/17 Python
python关于变量名的基础知识点
2020/03/03 Python
Python使用ElementTree美化XML格式的操作
2020/03/06 Python
CSS3实现多重边框的方法总结
2016/05/31 HTML / CSS
海淘零差价,宝贝全球购: 宝贝格子
2016/08/24 全球购物
数学与统计学院学生个人职业生涯规划书
2014/02/10 职场文书
大学生个人自荐信
2014/02/24 职场文书
领导接待方案
2014/03/13 职场文书
安全承诺书格式
2014/05/21 职场文书
创新社会管理心得体会
2014/09/12 职场文书
职工擅自离岗检讨书
2014/09/23 职场文书
2014年审计工作总结
2014/11/17 职场文书
2015国庆66周年宣传语
2015/07/14 职场文书
Python语言中的数据类型-序列
2022/02/24 Python
SpringBoot使用ip2region获取地理位置信息的方法
2022/06/21 Java/Android