最近在學習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/ 進行檢視。
功能很簡單:
可以看到,我們在這個頁面上做了兩個圖檔輪播效果,而且兩個圖檔輪播的時間間隔與動畫時長都是獨立的,互不幹擾。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL0YDNwQDM2gDOtEjM0cTM4ETMxAzMxETNxAjMtYDOxYDM28CXxETNxAjMvwlN4EjNwYzLcd2bsJ2Lc12bj5ycn9Gbi52YuUTMwIzcldWYtl2Lc9CX6MHc0RHaiojIsJye.png)
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值,進而達到滑動切換的效果。