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