webpack中如何使用雪碧图

一、什么是雪碧图?

CSS雪碧 即CSS Sprite,也有人叫它CSS精灵,是一种CSS图像合并技术,该方法是将小图标和背景图像合并到一张图片上,然后利用css的背景定位来显示需要显示的图片部分。

二:为什么要用雪碧图

结合我们公司的需求来说,因为有很多组件,每个组件下有大概50张图片,每张图片是一个请求,也就是发了300多个请求,这样是很可怕的,所以为了优化性能,减少http请求,决定采用雪碧图的形式。

雪碧图是将你想要的很多张图片整理成一张图片,然后通过background-*来进行图片识别和定位来达到之前的效果。

三:如何使用雪碧图

雪碧图在之前有很多方式,如ps之类,现在最佳的方案还是在webpack-spritesmith

我其实对webpack并不是很了解,我现在列出使用方法和我在使用webpack时候遇到的问题。

1.安装

执行命令行npm install --save-dev webpack-spritesmith

2.在webpack.config.js中写入

 var path = require('path')

 var SpritesmithPlugin = require('webpack-spritesmith')

 //自定义样式
 var templateFunction = function (data) {
   var shared = '.ico { background-size: TWpx THpx }'
        .replace('TW', data.sprites[0].total_width / 2)
        .replace('TH', data.sprites[0].total_height / 2)

   var perSprite = data.sprites.map(function (sprite) {
       return '&.element-N {\n  width: Wpx;\n  height: Hpx;\n  background-position: Xpx Ypx;\n}'
           .replace('N', sprite.name)
           .replace('W', sprite.width / 2)
           .replace('H', sprite.height / 2)
           .replace('X', sprite.offset_x / 2)
           .replace('Y', sprite.offset_y / 2)
           .replace('TW', sprite.total_width / 2)
           .replace('TH', sprite.total_height / 2)
   }).join('\n')

   return shared + '\n' + perSprite
 }

 module.exports = {
      ...
     module: {
         rules: [
             {test: /\.styl$/, use: [
                 'style-loader',
                 'css-loader',
                 'stylus-loader'
             ]},
             {test: /\.png$/, use: [
                 'file-loader?name=i/[hash].[ext]'
             ]}
         ]
     },
     resolve: {
         modules: ['node_modules', 'spritesmith-generated']
     },
     plugins: [
         new SpritesmithPlugin({
             src: { //引入路径
                 cwd: path.resolve(__dirname, 'src/images/ios/'),
                 glob: '*.png'
             },
             target: { //输出路径
                 image: path.resolve(__dirname, 'src/spritesmith-generated/ios.png'),
                 css: [
                   [path.resolve(__dirname, 'src/spritesmith-generated/sprite-1.css'), {
                       format: 'function_based_template'
                   }],
                   [path.resolve(__dirname, 'src/spritesmith-generated/sprite-2.css'), {
                       format: 'handlebars_based_template'
                   }]
                 ]
             },
             customTemplates: {
               'function_based_template': templateFunction, //自定义输出什么样的css样式
             },
             apiOptions: {
                 cssImageRef: 'ios.png'
             }
         })
     ]
 }

3.根据地址更改后执行命令

wbpack

其实这样已经满足了大部分需求,根据需要将你所在的输入和输出地址进行更改即可,可以设置自己想要设置的的css(style-components、styl等),然后直接复制在自己的项目css文件,很有灵活性。

四:需要注意的点

我有的时候指定不同文件下的图片合成一张雪碧图,那该如何呢

例如我的需求是:

  • resources
    • ios
      • images
    • ant
      • images
    • ios
      • images
    • ...

翻译: resources下有几个文件夹(ios、ant、ios),相对应下面images文件夹放着各自对应的图片。

需要注意下,它是支持glob

src: { 
  //引入路径
  cwd: path.resolve(__dirname, 'src/images/ios/'),
  glob: '*.png' //这里进行更改
},

这里可以参考在这里根据需求进行设置http://www.globtester.com/

glob改成

@(wechat|element|ios)/images/*.png

效果

五:更深层次的需求

我其实是想在各自的文件夹下的图片,生成各自文件夹下的雪碧图和css,那该如何实现呢,我写了一部分,还没有写完,感觉遇到了技术难点,我呈现出代码,会继续优化来实现

var path = require('path')
var SpritesmithPlugin = require('webpack-spritesmith')

var platforms = ['android', 'ant', 'element', 'ios', 'wechat']//, 'windows']

// var url = 'ant'
const TARGET = process.env.TARGET

console.log({ TARGET })

module.exports = [TARGET].map(l => {
  console.log(l)
  const url = l

  const fn = (data) => {
    console.log(url)
    var shared = 'background-size: TWpx THpx\n'
        .replace('TW', data.sprites[0].total_width / 2)
        .replace('TH', data.sprites[0].total_height / 2)

    var perSprite = data.sprites.map(function (sprite) {
        return `&.${url}-N {\n  width: Wpx;\n  height: Hpx;\n  background-position: Xpx Ypx;\n}\n`
            .replace('N', sprite.name)
            .replace('W', sprite.width / 2)
            .replace('H', sprite.height / 2)
            .replace('X', sprite.offset_x / 2)
            .replace('Y', sprite.offset_y / 2)
            .replace('TW', sprite.total_width / 2)
            .replace('TH', sprite.total_height / 2)
    }).join('\n')

    return shared + '\n' + perSprite
  }

  return {
    module: {
        rules: [
            {test: /\.styl$/, use: [
                'style-loader',
                'css-loader',
                'stylus-loader'
            ]},
            {test: /\.png$/, use: [
                'file-loader?name=i/[hash].[ext]'
            ]}
        ]
    },
    entry: {
      [url]: path.join(__dirname, url),
    },
    output: {
      path: path.join(__dirname, '../parsed/', url),
      filename: '[name].css'
    },
    resolve: {
        modules: ['node_modules', 'spritesmith-generated']
    },
    plugins: [
        new SpritesmithPlugin({
            src: {
                cwd: path.resolve(__dirname, 'images/'+url+'/'),
                glob: '*.png' // '@(android|ant|element|ios|wechat|windows)/*.png'
            },
            target: {
                image: path.resolve(__dirname, '../parsed/'+url+'/'+url+'.png'),
                css: [
                    [path.resolve(__dirname, '../parsed/'+url+'/'+url+'.css'), {
                        format: 'function_based_template'
                    }]
                ]
            },
            customTemplates: {
                'function_based_template': fn
            }
        })
    ]
  }
})

以上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章