最近在学习webpack,正好拿了之前做的一个小组件,图片轮播来做了下练手,让我们一起来初步感受下webpack的神奇魅力。
webpack是一个前端的打包管理工具,大家可以前往:http://webpack.github.io/ 作详细了解。相对于之前的前端模块打包工具,
个人认为webpack至少拥有以下值得我们拿来一用的优点:
- js/css/img/html等等都是静态资源,都可以通过webpack进行打包处理
- 所有资源都可以按需加载,避免了之前的加载器把所有资源打包在一个文件,导致文件过大而且不需要的模块也加载出来;同时也避免了将资源按照独立文件进行打包,从而导致大量的HTTP请求造成降低页面性能
- 提供了很多前端打包所需要的配套小插件,比如:JS压缩,JSHint,图片压缩等等
- 完美兼容了AMD和CommonJS以及ES6语法,大家之前写的模块不用再重新进行改造了。
当前很多优点是我没有提及的或者还没有了解到的,但是目前这几个优点来说,已经算是可以完全满足我们在项目中的实际打包需求了。
这次算是把webpack模块打包与之前的一篇文章:http://www.cnblogs.com/souvenir/p/4977407.html 中提及的图片轮播二者结合起来,一起与大家进行分享。
1.先看DEMO
同样的,这次我也将这次写的DEMO代码分享到Github上,大家可以自行前往查看源码: https://github.com/xiaoyunchen/easySlide/
最后的页面效果大家可以访问 http://xiaoyunchen.github.io/easySlide/ 进行查看。
功能很简单:
可以看到,我们在这个页面上做了两个图片轮播效果,而且两个图片轮播的时间间隔与动画时长都是独立的,互不干扰。
2.准备工作
在开始学习webpack打包之前,我们先要做一些准备工作。第一步当然安装nodejs了,然后再使用npm命令安装webpack以及我们所需要的几个加载器:
npm install webpack -g
npm install jquery@1
npm install css-loader
npm install style-loader
3.webpack打包
看完最终的效果后,我们接下来继续来看这个简单的项目是如何使用webpack进行打包的。
首先大家在Github可以先打开项目的源码,可以看到项目的目录结构是这样的:
最外层有几个文件:
index.html --- 项目入口页面
package.json --- nodejs环境下用于描述模块包结构的文件
webpack.config.js --- webpack配置文件,稍后我们将重点分析这个配置文件
然后就是三个目录:
src --- 项目开发的源码
node_modules --- 项目打包中用到的node模块
dist --- 打包后最终的输出目录
再来看看src目录的结构,先按照常规的css/js/img进行划分,然后每个目录下在按照功能模块进行子目录划分:
module --- 通用组件
page --- 页面应用
vendor ---引用第三方组件
这是我个人的一个目录划分,实际的项目中大家可以根据项目或者公司的需要进行调整。
接着来看入口文件:index.js
1 (function(){
2 //引入公共CSS与页面CSS
3 require('../../css/vendor/reset.css');
4 require('../../css/page/index.css');
5
6 //引入并创建多个独立slideModule模块
7 var slideModule=require("../module/slide.js");
8 new slideModule({dom:$('[node-type="iccAdvisorPicture"]')});
9 new slideModule({
10 dom:$('[node-type="iccAdvisorPicture2"]'),
11 delay:4000,
12 duration:800
13 });
14 })();
代码量14行,整体来说还算是比较清爽的,这都得益于模块打包。
在这里,我们定义并执行了一个闭包函数。主要功能就是两个:
1.加载改页面上的公共CSS (别忘了css也是一种资源,我们可以通过webpack来进行打包加载)
2.引入了我们自定义了slideModule组件,然后使用该组件创建了两个图片轮播的实例
就是这么简洁,这也是我们所希望的,将功能按模块进行开发,使用的时候按照需要进行加载。
我们先不管slideModule是如何具体实现这个功能的,我们接着来看webpack的配置文件:
1 var path=require('path');
2 var webpack = require('webpack');
3 module.exports = {
4 entry: {
5 index:"./src/js/page/index.js",
6 },
7 output: {
8 path: path.join(__dirname,'dist'),
9 filename: "bundle.js"
10 },
11 module: {
12 loaders: [ //css加载器
13 { test: /\.css$/, loader: "style!css" }
14 ]
15 },
16 plugins:[
17 new webpack.ProvidePlugin({ //加载jq
18 $: 'jquery'
19 }),
20 new webpack.optimize.UglifyJsPlugin({ //压缩代码
21 compress: {
22 warnings: false
23 },
24 except: ['$super', '$', 'exports', 'require'] //排除关键字
25 })
26 ]
27 };
关于这个配置文件中详细参数与属性,大家可以前往webpack官网进行查看。这里我们主要讲解下这个配置文件所要达到的目的。
entry:入口。注意这里的路径是相对于webpack.config.js的路径,也就是根目录
path:主要是定义了打包后的文件存放目录和文件名,这里我们是将打包后的文件存放在/dist/bundle.js文件中。
module-loaders:加载器。这里我们只使用了一个CSS加载器
plugins:插件。第一个是jquery,我们将jquery加载进行项目中并将$作为全局变量返回,所以在任何位置都可以使用jquery而且无需更多配置。
第二个是对输出的的js代码进行压缩,这一步是可选的,一般也可以将有部署服务器将部署到正式环境之前在进行压缩处理。
OK,接下来我们就可以使用webpack进行打包了,在命令行切换当前项目所在目录,然后打包使用:
webpack -w
然后仅能看到类似于下图的输出结果,没有任何报错的话说明打包已经成功:
-w 是打包选项,watch的意思,webpack将监控项目的文件如果有修改变动的时候,将会自动运行打包命令
其他的选项还有:-p 压缩代码。但是一般我们都将代码压缩卸载配置文件中。
-d 输出sourcemap
打包成功后我们在index.html页面中就只需要引入/dist/bundle.js即可,连css都无需再引入。
然后就可以运行页面查看具体的效果。
OK,webpack打包过程大概就是这样,相信大家可能会有一些疑问,这不就是把所有资源文件都放在一个文件里面吗,如果项目太大的话,那这个文件还不得很大了。
这里就涉及到之前说的webpack可以实现按需加载模块,我们将在下一篇为大家进行介绍有关内容。
4.slideModule 模块
接下来我们来看图片轮播这个组件是如何实现的,以及在实现的过程如何使用webpack语法进行资源加载。
这是我们的代码截图,所有的代码同样都是在一个闭包函数中的,这样做可以避免对全局变量window的污染。
第2行我们使用require引入了一个css文件,这个CSS是专属于图片轮播模块的,在模块里进行引入,屏蔽具体实现,外面的js在使用的使用不用再关心是不是还要在
引入额外的css,只需要一句话引入然后完成相应的功能。
第4行定义了一个默认配置对象,用于定义模块的一些基础配置,如果在使用的时候不传入对应的参数我们将默认使用该默认配置。
第12行定义了一个方法,这个方法其实也就是我们图片滑动模块的构建函数,在这个构造函数里我们首先将外层传入的配置参数与默认参数进行合并。
然后在根据dom选择器重新计算图片数量。
在19行我们使用prototype对slideModule这个方法进行了扩展,增加了几个处理方法
1 slideModule.prototype={
2 init:function(){
3 this.bindMouseEvent();
4 this.autoPlay();
5 },
6 slidePic:function(){ //切换图片
7 var that=this;
8 this.config.dom.animate({'marginLeft':-(this.config.current==this.config.total?0:this.config.current)*this.config.width+'px'},this.config.duration,function(){
9 that.config.current++;
10 if(that.config.current>that.config.total){
11 that.config.current=1;
12 }
13 });
14 },
15 autoPlay:function(){ //自动切换
16 var that=this;
17 this.config.timer=setInterval(function(){
18 that.slidePic();
19 }, this.config.delay);
20 },
21 bindMouseEvent:function(){ //绑定鼠标移入/移除事件
22 var that=this;
23 this.config.dom.mouseenter(function(){
24 if(that.config.timer){
25 clearInterval(that.config.timer);
26 }
27 });
28 this.config.dom.mouseleave(function(){
29 that.autoPlay();
30 });
31 }
32 };
init:模块初始化方法,负责调用对应函数对模块进行功能初始化
slidePic:图片切换的具体实现方法,这里使用了jquery的animate方法,创建了一个动画,将图片外层父级元素marginLeft减少一个图片的宽度
整个动画的时长来自于配置信息。
滑动动画结束后将修改当前显示的是第几个图片,如果超过最大数量的话就设置回1,让动画下次从头开始。
autoPlay:创建一个定时器,每隔一段时间自动执行slidePic来切换图片,从而实现了自动轮播的效果。
这里之所以使用闭包函数,是因为作用域的原因,详细的介绍大家可以查看之前的文章。
bindMouseEvent:这里增加了两个鼠标事件,当鼠标移入滑动组件区域内时,清除掉定时器暂时动画,当鼠标离开时重新开启定时器,继续执行轮播动画
图片轮播的实现原理大概是这样的:
最外层的div宽度固定,与单个图片宽度(加载边距)相同,同时设置了超出的部分隐藏显示;然后ul宽度设置为很大, 至少需要N呗的图片宽度,可以让所有图片放在一行
然后定时器来改变ul的margin-left值,从而达到滑动切换的效果。