最近在學習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值,從而達到滑動切換的效果。